Kernels:
Trusted publisher
Uploaded using `kernel-builder`.
Browse filesThis view is limited to 50 files because it contains too many changes. See raw diff
- README.md +1 -1
- build/torch-cuda/__init__.py +2 -0
- build/torch-cuda/_ops.py +1 -1
- build/torch-cuda/{ops/backends/__init__.py → backends.py} +156 -114
- build/torch-cuda/layers.py +10 -0
- build/torch-cuda/metadata.json +264 -223
- build/torch-cuda/metadata.json.sigstore +1 -1
- build/torch-cuda/modules/__init__.py +86 -5
- build/{torch-xpu/ops/cp → torch-cuda/modules/activations}/__init__.py +28 -21
- build/torch-cuda/modules/{activations.py → activations/ops.py} +302 -359
- build/torch-cuda/modules/backends/__init__.py +0 -17
- build/torch-cuda/modules/backends/triton_ascend/__init__.py +0 -422
- build/torch-cuda/modules/backends/triton_ascend/activations.py +0 -931
- build/torch-cuda/modules/backends/triton_ascend/causal_conv1d.py +0 -1175
- build/torch-cuda/modules/backends/triton_ascend/fused_cross_entropy.py +0 -469
- build/torch-cuda/modules/backends/triton_ascend/fused_kl_div.py +0 -188
- build/torch-cuda/modules/backends/triton_ascend/fused_linear_cross_entropy.py +0 -347
- build/torch-cuda/modules/backends/triton_ascend/grpo.py +0 -266
- build/torch-cuda/modules/backends/triton_ascend/layernorm.py +0 -355
- build/torch-cuda/modules/backends/triton_ascend/rotary.py +0 -211
- build/{torch-xpu/modules/conv/triton → torch-cuda/modules/causal_conv1d}/__init__.py +10 -3
- build/torch-cuda/modules/causal_conv1d/backends/__init__.py +6 -0
- build/torch-cuda/modules/{conv → causal_conv1d/backends}/cuda/__init__.py +2 -6
- build/torch-cuda/modules/causal_conv1d/backends/cuda/cp.py +98 -0
- build/{torch-xpu/modules/conv → torch-cuda/modules/causal_conv1d/backends}/cuda/ops.py +68 -87
- build/torch-cuda/modules/causal_conv1d/backends/gluon.py +417 -0
- build/torch-cuda/modules/{conv/cp/ops.py → causal_conv1d/cp.py} +149 -77
- build/torch-cuda/modules/{conv/triton/kernels.py → causal_conv1d/ops.py} +766 -125
- build/torch-cuda/modules/conv/causal_conv1d.py +0 -129
- build/torch-cuda/modules/conv/cuda/ops.py +0 -233
- build/torch-cuda/modules/conv/short_conv.py +0 -250
- build/torch-cuda/modules/conv/triton/ops.py +0 -424
- build/torch-cuda/modules/convolution.py +0 -42
- build/torch-cuda/modules/feature_map.py +1 -2
- build/torch-cuda/modules/fused_bitlinear.py +76 -559
- build/torch-cuda/modules/fused_cross_entropy.py +0 -459
- build/torch-cuda/modules/fused_cross_entropy/__init__.py +15 -0
- build/torch-cuda/modules/fused_cross_entropy/gluon.py +402 -0
- build/torch-cuda/modules/fused_cross_entropy/ops.py +538 -0
- build/torch-cuda/modules/fused_kl_div/__init__.py +11 -0
- build/torch-cuda/modules/{fused_kl_div.py → fused_kl_div/ops.py} +63 -113
- build/torch-cuda/modules/fused_linear_cross_entropy/__init__.py +15 -0
- build/torch-cuda/modules/{fused_linear_cross_entropy.py → fused_linear_cross_entropy/ops.py} +211 -443
- build/torch-cuda/modules/fused_norm_gate.py +0 -1245
- build/{torch-xpu/modules/conv/cp → torch-cuda/modules/grpo}/__init__.py +3 -5
- build/torch-cuda/modules/{grpo.py → grpo/ops.py} +77 -117
- build/torch-cuda/modules/l2warp.py +5 -6
- build/torch-cuda/modules/{conv/long_conv.py → long_conv.py} +45 -63
- build/{torch-xpu/modules → torch-cuda/modules/norm}/__init__.py +20 -22
- build/{torch-xpu/modules → torch-cuda/modules/norm}/fused_norm_gate.py +197 -220
README.md
CHANGED
|
@@ -11,7 +11,7 @@ This is the repository card of kernels-community/fla that has been pushed on the
|
|
| 11 |
# make sure `kernels` is installed: `pip install -U kernels`
|
| 12 |
from kernels import get_kernel
|
| 13 |
|
| 14 |
-
kernel_module = get_kernel("kernels-community/fla", version=
|
| 15 |
chunk_kda = kernel_module.chunk_kda
|
| 16 |
|
| 17 |
chunk_kda(...)
|
|
|
|
| 11 |
# make sure `kernels` is installed: `pip install -U kernels`
|
| 12 |
from kernels import get_kernel
|
| 13 |
|
| 14 |
+
kernel_module = get_kernel("kernels-community/fla", version=2)
|
| 15 |
chunk_kda = kernel_module.chunk_kda
|
| 16 |
|
| 17 |
chunk_kda(...)
|
build/torch-cuda/__init__.py
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
|
|
|
|
|
| 1 |
from . import layers
|
| 2 |
from .ops.gated_delta_rule import chunk_gated_delta_rule, fused_recurrent_gated_delta_rule
|
| 3 |
from .ops.kda import chunk_kda, fused_recurrent_kda
|
|
|
|
| 1 |
+
__version__ = "0.6.0"
|
| 2 |
+
|
| 3 |
from . import layers
|
| 4 |
from .ops.gated_delta_rule import chunk_gated_delta_rule, fused_recurrent_gated_delta_rule
|
| 5 |
from .ops.kda import chunk_kda, fused_recurrent_kda
|
build/torch-cuda/_ops.py
CHANGED
|
@@ -25,7 +25,7 @@ def get_backend() -> str:
|
|
| 25 |
|
| 26 |
def _find_ops_name() -> str:
|
| 27 |
kernel_name = "fla"
|
| 28 |
-
unique_id = "
|
| 29 |
backend = get_backend()
|
| 30 |
return f"_{kernel_name}_{backend}_{unique_id}"
|
| 31 |
|
|
|
|
| 25 |
|
| 26 |
def _find_ops_name() -> str:
|
| 27 |
kernel_name = "fla"
|
| 28 |
+
unique_id = "faa8674"
|
| 29 |
backend = get_backend()
|
| 30 |
return f"_{kernel_name}_{backend}_{unique_id}"
|
| 31 |
|
build/torch-cuda/{ops/backends/__init__.py → backends.py}
RENAMED
|
@@ -5,26 +5,25 @@
|
|
| 5 |
# For a list of all contributors, visit:
|
| 6 |
# https://github.com/fla-org/flash-linear-attention/graphs/contributors
|
| 7 |
|
| 8 |
-
"""
|
| 9 |
|
| 10 |
from __future__ import annotations
|
| 11 |
|
| 12 |
-
import
|
| 13 |
import logging
|
| 14 |
import os
|
| 15 |
-
import threading
|
| 16 |
from collections.abc import Callable
|
| 17 |
from functools import cache, wraps
|
|
|
|
| 18 |
from typing import Any, ClassVar, TypeVar
|
| 19 |
|
| 20 |
import torch
|
| 21 |
|
| 22 |
-
from .
|
| 23 |
|
| 24 |
logger = logging.getLogger(__name__)
|
| 25 |
F = TypeVar('F', bound=Callable)
|
| 26 |
|
| 27 |
-
|
| 28 |
_DISPATCH_DISABLED = os.environ.get("FLA_DISABLE_BACKEND_DISPATCH") == "1"
|
| 29 |
if _DISPATCH_DISABLED:
|
| 30 |
logger.info("[FLA Backend] FLA_DISABLE_BACKEND_DISPATCH=1 — all dispatch bypassed")
|
|
@@ -36,6 +35,7 @@ class BaseBackend:
|
|
| 36 |
Attributes:
|
| 37 |
backend_type (str, Optional):
|
| 38 |
Identifier for the backend type, used to distinguish different backend implementations.
|
|
|
|
| 39 |
Default: `"base"`.
|
| 40 |
package_name (str, Optional):
|
| 41 |
Name of the external package required by the backend.
|
|
@@ -52,10 +52,20 @@ class BaseBackend:
|
|
| 52 |
|
| 53 |
backend_type: ClassVar[str] = "base"
|
| 54 |
package_name: ClassVar[str | None] = None
|
| 55 |
-
env_var:
|
| 56 |
default_enable: ClassVar[bool] = True
|
| 57 |
-
# Lower number = higher priority, default is 5
|
| 58 |
priority: ClassVar[int] = 5
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 59 |
|
| 60 |
@classmethod
|
| 61 |
def is_available(cls) -> bool:
|
|
@@ -63,161 +73,193 @@ class BaseBackend:
|
|
| 63 |
return True
|
| 64 |
return find_spec_cached(cls.package_name) is not None
|
| 65 |
|
| 66 |
-
|
| 67 |
-
|
| 68 |
-
|
|
|
|
| 69 |
return True
|
| 70 |
-
default_value = "1" if
|
| 71 |
-
return os.environ.get(
|
| 72 |
|
| 73 |
@classmethod
|
| 74 |
@cache
|
| 75 |
def can_use(cls) -> bool:
|
| 76 |
-
return cls.is_available() and cls.is_enabled()
|
| 77 |
|
| 78 |
-
def verify(self,
|
| 79 |
"""Check if backend can handle the function call."""
|
| 80 |
-
verifier_name = f"{
|
| 81 |
-
verifier = getattr(self, verifier_name, None)
|
| 82 |
if verifier is None:
|
| 83 |
return True, None
|
| 84 |
|
| 85 |
try:
|
| 86 |
return verifier(*args, **kwargs)
|
| 87 |
-
except Exception as
|
| 88 |
-
return False, str(
|
| 89 |
|
| 90 |
|
| 91 |
-
|
| 92 |
-
|
| 93 |
-
}
|
| 94 |
|
|
|
|
|
|
|
| 95 |
|
| 96 |
-
|
| 97 |
-
|
|
|
|
|
|
|
| 98 |
|
| 99 |
-
_registries: ClassVar[dict[str, BackendRegistry]] = {}
|
| 100 |
-
_initialized: ClassVar[set[str]] = set()
|
| 101 |
-
_init_lock: ClassVar[threading.Lock] = threading.Lock()
|
| 102 |
|
| 103 |
-
|
| 104 |
-
|
| 105 |
-
self._backends: dict[str, BaseBackend] = {}
|
| 106 |
-
self._active: BaseBackend | None = None
|
| 107 |
-
self._lock = threading.RLock()
|
| 108 |
-
self._logged: set[str] = set()
|
| 109 |
-
BackendRegistry._registries[operation_name] = self
|
| 110 |
|
| 111 |
-
|
| 112 |
-
|
| 113 |
-
|
| 114 |
-
self._backends[backend.backend_type] = backend
|
| 115 |
-
# Update active backend based on priority
|
| 116 |
-
self._update_active_backend()
|
| 117 |
|
| 118 |
-
|
| 119 |
-
|
|
|
|
| 120 |
|
| 121 |
-
Backends with the same priority are sorted by registration order.
|
| 122 |
-
"""
|
| 123 |
-
return sorted(
|
| 124 |
-
self._backends.values(),
|
| 125 |
-
key=lambda b: (b.priority, list(self._backends.values()).index(b))
|
| 126 |
-
)
|
| 127 |
|
| 128 |
-
|
| 129 |
-
|
| 130 |
-
for backend in self._get_sorted_backends():
|
| 131 |
-
if backend.can_use():
|
| 132 |
-
self._active = backend
|
| 133 |
-
return
|
| 134 |
|
| 135 |
-
|
| 136 |
-
|
| 137 |
-
|
|
|
|
| 138 |
|
| 139 |
@classmethod
|
| 140 |
-
def
|
| 141 |
-
|
| 142 |
-
|
| 143 |
-
return
|
| 144 |
|
| 145 |
-
with cls._init_lock:
|
| 146 |
-
if operation in cls._initialized:
|
| 147 |
-
return
|
| 148 |
|
| 149 |
-
|
| 150 |
-
|
| 151 |
-
operation,
|
| 152 |
-
f'fla.ops.{operation}.backends',
|
| 153 |
-
)
|
| 154 |
-
with contextlib.suppress(ImportError):
|
| 155 |
-
__import__(module_path, fromlist=[''])
|
| 156 |
|
| 157 |
-
|
|
|
|
|
|
|
|
|
|
| 158 |
|
|
|
|
|
|
|
|
|
|
| 159 |
|
| 160 |
-
def
|
| 161 |
-
|
|
|
|
| 162 |
|
| 163 |
-
|
| 164 |
-
|
| 165 |
-
|
| 166 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 167 |
if _DISPATCH_DISABLED:
|
| 168 |
-
return
|
| 169 |
-
|
| 170 |
|
| 171 |
-
@wraps(
|
| 172 |
def wrapper(*args, **kwargs) -> Any:
|
| 173 |
-
|
| 174 |
-
|
| 175 |
-
|
| 176 |
-
registry = BackendRegistry._registries.get(operation)
|
| 177 |
-
if registry is None:
|
| 178 |
-
return func(*args, **kwargs)
|
| 179 |
-
|
| 180 |
-
# Iterate through all registered backends sorted by priority
|
| 181 |
-
# to find one that can handle this call
|
| 182 |
-
backends_list = registry._get_sorted_backends()
|
| 183 |
-
|
| 184 |
-
for be in backends_list:
|
| 185 |
-
# Avoid be.can_use(): its @cache wrapper breaks torch.compile tracing.
|
| 186 |
-
if not (be.is_available() and be.is_enabled()):
|
| 187 |
continue
|
| 188 |
|
| 189 |
-
|
| 190 |
-
if not
|
| 191 |
-
|
| 192 |
-
if
|
| 193 |
-
|
| 194 |
logger.info(
|
| 195 |
-
f"[FLA Backend] {
|
| 196 |
f"rejected: {reason}"
|
| 197 |
)
|
| 198 |
continue
|
| 199 |
|
| 200 |
-
|
| 201 |
-
if
|
| 202 |
continue
|
| 203 |
|
| 204 |
-
result =
|
| 205 |
|
| 206 |
-
log_key = f"{
|
| 207 |
-
if log_key not in
|
| 208 |
-
|
| 209 |
-
logger.info(f"[FLA Backend] {
|
| 210 |
|
| 211 |
return result
|
| 212 |
|
| 213 |
-
|
| 214 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 215 |
|
| 216 |
-
# Dispatch performs runtime backend selection; keep it out of torch.compile graphs.
|
| 217 |
-
wrapper = torch.compiler.disable(wrapper)
|
| 218 |
-
|
| 219 |
-
return wrapper
|
| 220 |
return decorator
|
| 221 |
|
| 222 |
|
| 223 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 5 |
# For a list of all contributors, visit:
|
| 6 |
# https://github.com/fla-org/flash-linear-attention/graphs/contributors
|
| 7 |
|
| 8 |
+
"""Backend registration and runtime selection."""
|
| 9 |
|
| 10 |
from __future__ import annotations
|
| 11 |
|
| 12 |
+
import importlib
|
| 13 |
import logging
|
| 14 |
import os
|
|
|
|
| 15 |
from collections.abc import Callable
|
| 16 |
from functools import cache, wraps
|
| 17 |
+
from inspect import unwrap
|
| 18 |
from typing import Any, ClassVar, TypeVar
|
| 19 |
|
| 20 |
import torch
|
| 21 |
|
| 22 |
+
from .utils import find_spec_cached, has_usable_nvcc
|
| 23 |
|
| 24 |
logger = logging.getLogger(__name__)
|
| 25 |
F = TypeVar('F', bound=Callable)
|
| 26 |
|
|
|
|
| 27 |
_DISPATCH_DISABLED = os.environ.get("FLA_DISABLE_BACKEND_DISPATCH") == "1"
|
| 28 |
if _DISPATCH_DISABLED:
|
| 29 |
logger.info("[FLA Backend] FLA_DISABLE_BACKEND_DISPATCH=1 — all dispatch bypassed")
|
|
|
|
| 35 |
Attributes:
|
| 36 |
backend_type (str, Optional):
|
| 37 |
Identifier for the backend type, used to distinguish different backend implementations.
|
| 38 |
+
`FLA_<BACKEND_TYPE>` enables all backends of this type, overriding individual switches set to `0`.
|
| 39 |
Default: `"base"`.
|
| 40 |
package_name (str, Optional):
|
| 41 |
Name of the external package required by the backend.
|
|
|
|
| 52 |
|
| 53 |
backend_type: ClassVar[str] = "base"
|
| 54 |
package_name: ClassVar[str | None] = None
|
| 55 |
+
env_var: str | None = None
|
| 56 |
default_enable: ClassVar[bool] = True
|
|
|
|
| 57 |
priority: ClassVar[int] = 5
|
| 58 |
+
implementation: Callable | None = None
|
| 59 |
+
verifier: Callable | None = None
|
| 60 |
+
|
| 61 |
+
def __init__(self, *, env_var: str | None = None):
|
| 62 |
+
if env_var is not None:
|
| 63 |
+
self.env_var = env_var
|
| 64 |
+
|
| 65 |
+
def get_implementation(self, function_name: str) -> Callable | None:
|
| 66 |
+
if self.implementation is not None:
|
| 67 |
+
return self.implementation
|
| 68 |
+
return getattr(self, function_name, None)
|
| 69 |
|
| 70 |
@classmethod
|
| 71 |
def is_available(cls) -> bool:
|
|
|
|
| 73 |
return True
|
| 74 |
return find_spec_cached(cls.package_name) is not None
|
| 75 |
|
| 76 |
+
def is_enabled(self) -> bool:
|
| 77 |
+
if self.env_var is None:
|
| 78 |
+
return True
|
| 79 |
+
if os.environ.get(f"FLA_{self.backend_type.upper()}", "0") != "0":
|
| 80 |
return True
|
| 81 |
+
default_value = "1" if self.default_enable else "0"
|
| 82 |
+
return os.environ.get(self.env_var, default_value) != "0"
|
| 83 |
|
| 84 |
@classmethod
|
| 85 |
@cache
|
| 86 |
def can_use(cls) -> bool:
|
| 87 |
+
return cls.is_available() and cls().is_enabled()
|
| 88 |
|
| 89 |
+
def verify(self, function_name: str, *args, **kwargs) -> tuple[bool, str | None]:
|
| 90 |
"""Check if backend can handle the function call."""
|
| 91 |
+
verifier_name = f"{function_name}_verifier"
|
| 92 |
+
verifier = self.verifier or getattr(self, verifier_name, None)
|
| 93 |
if verifier is None:
|
| 94 |
return True, None
|
| 95 |
|
| 96 |
try:
|
| 97 |
return verifier(*args, **kwargs)
|
| 98 |
+
except Exception as error:
|
| 99 |
+
return False, str(error)
|
| 100 |
|
| 101 |
|
| 102 |
+
class TritonAscendBackend(BaseBackend):
|
| 103 |
+
"""Shared availability and selection policy for Ascend implementations."""
|
|
|
|
| 104 |
|
| 105 |
+
backend_type = 'triton_ascend'
|
| 106 |
+
priority = 0
|
| 107 |
|
| 108 |
+
@classmethod
|
| 109 |
+
def is_available(cls) -> bool:
|
| 110 |
+
from .utils import IS_NPU
|
| 111 |
+
return IS_NPU
|
| 112 |
|
|
|
|
|
|
|
|
|
|
| 113 |
|
| 114 |
+
class TileLangBackend(BaseBackend):
|
| 115 |
+
"""Shared availability and selection policy for TileLang implementations."""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 116 |
|
| 117 |
+
backend_type = 'tilelang'
|
| 118 |
+
package_name = 'tilelang'
|
| 119 |
+
env_var = 'FLA_TILELANG'
|
|
|
|
|
|
|
|
|
|
| 120 |
|
| 121 |
+
@classmethod
|
| 122 |
+
def is_available(cls) -> bool:
|
| 123 |
+
return super().is_available() and has_usable_nvcc()
|
| 124 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 125 |
|
| 126 |
+
class GluonBackend(BaseBackend):
|
| 127 |
+
"""NVIDIA GPU backend using Gluon kernels."""
|
|
|
|
|
|
|
|
|
|
|
|
|
| 128 |
|
| 129 |
+
backend_type = 'gluon'
|
| 130 |
+
package_name = 'triton.experimental.gluon'
|
| 131 |
+
env_var = 'FLA_GLUON'
|
| 132 |
+
default_enable = False
|
| 133 |
|
| 134 |
@classmethod
|
| 135 |
+
def is_available(cls) -> bool:
|
| 136 |
+
from .utils import IS_NVIDIA
|
| 137 |
+
return IS_NVIDIA and super().is_available()
|
|
|
|
| 138 |
|
|
|
|
|
|
|
|
|
|
| 139 |
|
| 140 |
+
class BackendRegistry:
|
| 141 |
+
"""Ordered backend candidates for an operation or entry point."""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 142 |
|
| 143 |
+
def __init__(self, operation_name: str):
|
| 144 |
+
self.operation_name = operation_name
|
| 145 |
+
self._backends: dict[str, BaseBackend] = {}
|
| 146 |
+
self._logged: set[str] = set()
|
| 147 |
|
| 148 |
+
def register(self, backend: BaseBackend) -> None:
|
| 149 |
+
"""Register or replace a backend by its type."""
|
| 150 |
+
self._backends[backend.backend_type] = backend
|
| 151 |
|
| 152 |
+
def _get_sorted_backends(self) -> list[BaseBackend]:
|
| 153 |
+
"""Lower priorities come first; ties retain registration order."""
|
| 154 |
+
return sorted(self._backends.values(), key=lambda backend: backend.priority)
|
| 155 |
|
| 156 |
+
def get_active(self) -> BaseBackend | None:
|
| 157 |
+
"""Return the first available and enabled backend, before call verification."""
|
| 158 |
+
for backend in self._get_sorted_backends():
|
| 159 |
+
if backend.is_available() and backend.is_enabled():
|
| 160 |
+
return backend
|
| 161 |
+
return None
|
| 162 |
+
|
| 163 |
+
def dispatch(self, default_function: F) -> F:
|
| 164 |
+
"""Select the first eligible backend, falling back to the decorated function."""
|
| 165 |
if _DISPATCH_DISABLED:
|
| 166 |
+
return default_function
|
| 167 |
+
function_name = default_function.__name__
|
| 168 |
|
| 169 |
+
@wraps(default_function)
|
| 170 |
def wrapper(*args, **kwargs) -> Any:
|
| 171 |
+
for backend in self._get_sorted_backends():
|
| 172 |
+
# avoid backend.can_use(): its @cache wrapper breaks torch.compile tracing.
|
| 173 |
+
if not (backend.is_available() and backend.is_enabled()):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 174 |
continue
|
| 175 |
|
| 176 |
+
accepted, reason = backend.verify(function_name, *args, **kwargs)
|
| 177 |
+
if not accepted:
|
| 178 |
+
rejection_key = f"{self.operation_name}:{function_name}:{backend.backend_type}:fail"
|
| 179 |
+
if rejection_key not in self._logged:
|
| 180 |
+
self._logged.add(rejection_key)
|
| 181 |
logger.info(
|
| 182 |
+
f"[FLA Backend] {self.operation_name}.{function_name} -> {backend.backend_type} "
|
| 183 |
f"rejected: {reason}"
|
| 184 |
)
|
| 185 |
continue
|
| 186 |
|
| 187 |
+
implementation = backend.get_implementation(function_name)
|
| 188 |
+
if implementation is None:
|
| 189 |
continue
|
| 190 |
|
| 191 |
+
result = implementation(*args, **kwargs)
|
| 192 |
|
| 193 |
+
log_key = f"{self.operation_name}:{function_name}:{backend.backend_type}"
|
| 194 |
+
if log_key not in self._logged:
|
| 195 |
+
self._logged.add(log_key)
|
| 196 |
+
logger.info(f"[FLA Backend] {self.operation_name}.{function_name} -> {backend.backend_type}")
|
| 197 |
|
| 198 |
return result
|
| 199 |
|
| 200 |
+
return default_function(*args, **kwargs)
|
| 201 |
+
|
| 202 |
+
# runtime backend selection must stay outside torch.compile graphs.
|
| 203 |
+
return torch.compiler.disable(wrapper)
|
| 204 |
+
|
| 205 |
+
|
| 206 |
+
_operation_registries: dict[str, BackendRegistry] = {}
|
| 207 |
+
_function_registries: dict[Callable, BackendRegistry] = {}
|
| 208 |
+
|
| 209 |
+
|
| 210 |
+
def _get_operation_registry(operation: str) -> BackendRegistry:
|
| 211 |
+
if operation not in _operation_registries:
|
| 212 |
+
_operation_registries[operation] = BackendRegistry(operation)
|
| 213 |
+
return _operation_registries[operation]
|
| 214 |
+
|
| 215 |
+
|
| 216 |
+
def _load_operation_registry(operation: str) -> BackendRegistry:
|
| 217 |
+
# an existing registry does not guarantee that all of the owner's backends are loaded.
|
| 218 |
+
importlib.import_module(f'.ops.{operation}.backends', __package__)
|
| 219 |
+
return _get_operation_registry(operation=operation)
|
| 220 |
+
|
| 221 |
+
|
| 222 |
+
def register(
|
| 223 |
+
entry_point: Callable | str,
|
| 224 |
+
*,
|
| 225 |
+
backend: type[BaseBackend] | None = None,
|
| 226 |
+
verifier: Callable | None = None,
|
| 227 |
+
env_var: str | None = None,
|
| 228 |
+
) -> Callable[[F], F]:
|
| 229 |
+
"""Register an implementation or adapter for a dispatched function or operation name."""
|
| 230 |
+
def decorator(implementation: F) -> F:
|
| 231 |
+
if _DISPATCH_DISABLED and not isinstance(entry_point, str):
|
| 232 |
+
return implementation
|
| 233 |
+
if isinstance(implementation, type):
|
| 234 |
+
registered_backend = implementation()
|
| 235 |
+
if backend is not None and backend.backend_type != registered_backend.backend_type:
|
| 236 |
+
raise ValueError('The registration backend must match the adapter backend_type')
|
| 237 |
+
else:
|
| 238 |
+
registered_backend = backend() if backend is not None else BaseBackend()
|
| 239 |
+
registered_backend.implementation = implementation
|
| 240 |
+
registered_backend.verifier = verifier
|
| 241 |
+
if env_var is not None:
|
| 242 |
+
registered_backend.env_var = env_var
|
| 243 |
+
if isinstance(entry_point, str):
|
| 244 |
+
registry = _get_operation_registry(operation=entry_point)
|
| 245 |
+
else:
|
| 246 |
+
registry = _function_registries[unwrap(entry_point)]
|
| 247 |
+
registry.register(registered_backend)
|
| 248 |
+
return implementation
|
| 249 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 250 |
return decorator
|
| 251 |
|
| 252 |
|
| 253 |
+
def dispatch(entry_point: F | str) -> F | Callable[[F], F]:
|
| 254 |
+
"""Allow backends to register replacements while retaining the original fallback."""
|
| 255 |
+
if isinstance(entry_point, str):
|
| 256 |
+
return _load_operation_registry(operation=entry_point).dispatch
|
| 257 |
+
if _DISPATCH_DISABLED:
|
| 258 |
+
return entry_point
|
| 259 |
+
registry = BackendRegistry(entry_point.__module__)
|
| 260 |
+
_function_registries[unwrap(entry_point)] = registry
|
| 261 |
+
|
| 262 |
+
return registry.dispatch(entry_point)
|
| 263 |
+
|
| 264 |
+
|
| 265 |
+
__all__ = ['BackendRegistry', 'BaseBackend', 'dispatch', 'register']
|
build/torch-cuda/layers.py
CHANGED
|
@@ -7,6 +7,8 @@ from .ops.kda import chunk_kda, fused_recurrent_kda
|
|
| 7 |
|
| 8 |
|
| 9 |
class FusedRMSNormGated(nn.Module):
|
|
|
|
|
|
|
| 10 |
def forward(self, hidden_states, gate=None):
|
| 11 |
return rms_norm_gated(
|
| 12 |
hidden_states,
|
|
@@ -22,6 +24,8 @@ class FusedRMSNormGated(nn.Module):
|
|
| 22 |
|
| 23 |
|
| 24 |
class chunk_kimi_delta_attention(nn.Module):
|
|
|
|
|
|
|
| 25 |
def forward(
|
| 26 |
self,
|
| 27 |
query,
|
|
@@ -54,6 +58,8 @@ class chunk_kimi_delta_attention(nn.Module):
|
|
| 54 |
|
| 55 |
|
| 56 |
class recurrent_kimi_delta_attention(nn.Module):
|
|
|
|
|
|
|
| 57 |
def forward(
|
| 58 |
self, query, key, value, g, beta, initial_state, output_final_state, use_qk_l2norm_in_kernel=False, **kwargs,
|
| 59 |
):
|
|
@@ -75,6 +81,8 @@ class recurrent_kimi_delta_attention(nn.Module):
|
|
| 75 |
|
| 76 |
|
| 77 |
class chunk_gated_delta_rule(nn.Module):
|
|
|
|
|
|
|
| 78 |
def forward(
|
| 79 |
self,
|
| 80 |
query,
|
|
@@ -107,6 +115,8 @@ class chunk_gated_delta_rule(nn.Module):
|
|
| 107 |
|
| 108 |
|
| 109 |
class recurrent_gated_delta_rule(nn.Module):
|
|
|
|
|
|
|
| 110 |
def forward(
|
| 111 |
self, query, key, value, g, beta, initial_state, output_final_state, use_qk_l2norm_in_kernel=False, **kwargs,
|
| 112 |
):
|
|
|
|
| 7 |
|
| 8 |
|
| 9 |
class FusedRMSNormGated(nn.Module):
|
| 10 |
+
can_torch_compile = True
|
| 11 |
+
|
| 12 |
def forward(self, hidden_states, gate=None):
|
| 13 |
return rms_norm_gated(
|
| 14 |
hidden_states,
|
|
|
|
| 24 |
|
| 25 |
|
| 26 |
class chunk_kimi_delta_attention(nn.Module):
|
| 27 |
+
can_torch_compile = True
|
| 28 |
+
|
| 29 |
def forward(
|
| 30 |
self,
|
| 31 |
query,
|
|
|
|
| 58 |
|
| 59 |
|
| 60 |
class recurrent_kimi_delta_attention(nn.Module):
|
| 61 |
+
can_torch_compile = True
|
| 62 |
+
|
| 63 |
def forward(
|
| 64 |
self, query, key, value, g, beta, initial_state, output_final_state, use_qk_l2norm_in_kernel=False, **kwargs,
|
| 65 |
):
|
|
|
|
| 81 |
|
| 82 |
|
| 83 |
class chunk_gated_delta_rule(nn.Module):
|
| 84 |
+
can_torch_compile = True
|
| 85 |
+
|
| 86 |
def forward(
|
| 87 |
self,
|
| 88 |
query,
|
|
|
|
| 115 |
|
| 116 |
|
| 117 |
class recurrent_gated_delta_rule(nn.Module):
|
| 118 |
+
can_torch_compile = True
|
| 119 |
+
|
| 120 |
def forward(
|
| 121 |
self, query, key, value, g, beta, initial_state, output_final_state, use_qk_l2norm_in_kernel=False, **kwargs,
|
| 122 |
):
|
build/torch-cuda/metadata.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
| 1 |
{
|
| 2 |
"name": "fla",
|
| 3 |
-
"id": "
|
| 4 |
-
"version":
|
| 5 |
"kernels-minver": "0.14.0",
|
| 6 |
"license": "MIT",
|
| 7 |
"python-depends": [
|
|
@@ -14,297 +14,338 @@
|
|
| 14 |
"digest": {
|
| 15 |
"algorithm": "sha256",
|
| 16 |
"files": {
|
| 17 |
-
"__init__.py": "
|
| 18 |
-
"_ops.py": "
|
| 19 |
-
"
|
| 20 |
-
"
|
| 21 |
-
"modules/
|
| 22 |
-
"modules/
|
| 23 |
-
"modules/
|
| 24 |
-
"modules/
|
| 25 |
-
"modules/backends/
|
| 26 |
-
"modules/backends/
|
| 27 |
-
"modules/backends/
|
| 28 |
-
"modules/backends/
|
| 29 |
-
"modules/backends/
|
| 30 |
-
"modules/
|
| 31 |
-
"modules/
|
| 32 |
-
"modules/
|
| 33 |
-
"modules/
|
| 34 |
-
"modules/
|
| 35 |
-
"modules/
|
| 36 |
-
"modules/
|
| 37 |
-
"modules/
|
| 38 |
-
"modules/
|
| 39 |
-
"modules/
|
| 40 |
-
"modules/
|
| 41 |
-
"modules/
|
| 42 |
-
"modules/
|
| 43 |
-
"modules/
|
| 44 |
-
"modules/
|
| 45 |
-
"modules/fused_bitlinear.py": "lWTe4Ym60A+rHZTdQ6cZqa1Cje5vG/xMWvzLSAzLpQc=",
|
| 46 |
-
"modules/fused_cross_entropy.py": "si+ZNK/vu/TERnt/v2/Tm+ZBfn3poUoPDDTuJmrEuYM=",
|
| 47 |
-
"modules/fused_kl_div.py": "IDl78EMB9KXWmbV2cflnbXmcQpzdoqkwlEj4tvAPsbA=",
|
| 48 |
-
"modules/fused_linear_cross_entropy.py": "SruIxSe0Hhlf7n0upOldvn9HwOfL6XQ42N6qGZC6aOA=",
|
| 49 |
-
"modules/fused_norm_gate.py": "LAOhNgUSEiIU3Y5Ya5EHRjMAxHT0StODm04AUcL4Nys=",
|
| 50 |
-
"modules/grpo.py": "JPZnSGESIMmHDVkfYDSUzbm1qb2vY6dmDmFvSMI53RU=",
|
| 51 |
-
"modules/l2norm.py": "LchUl4mEXyx2cgHPuNgUhkorbNeuN+P7SfJyGXX0OyI=",
|
| 52 |
-
"modules/l2warp.py": "5oJlj6JRXBGe5ZANNnUA8GLIjlzXCnddtz2lwgKn6WA=",
|
| 53 |
-
"modules/layernorm.py": "1QhCZYF7pFRmZTxCWC55oG1uB6Lak5RXYca8MF5q5SA=",
|
| 54 |
-
"modules/layernorm_gated.py": "s/c/gRsZ3O6jXwY3b9owPaN1QAoOvsSevWuW2EXuJjE=",
|
| 55 |
"modules/mlp.py": "q09Zw5Bttqq27hnlybbQ9ncr0jSw1UCrJH2Ewh9roV4=",
|
| 56 |
-
"modules/
|
| 57 |
-
"modules/
|
| 58 |
-
"modules/
|
| 59 |
-
"modules/
|
| 60 |
-
"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 61 |
"ops/abc/__init__.py": "WwLiIkYi3xJ5RiG/bOCNNRaeeqmMuIPT6n1g23qfpDg=",
|
| 62 |
-
"ops/abc/chunk.py": "
|
| 63 |
"ops/abc/naive.py": "AZ3uz9eDvycW3gTwZuv9J4k86KndfQMZiLBFyPmzsLw=",
|
|
|
|
|
|
|
|
|
|
|
|
|
| 64 |
"ops/attn/__init__.py": "gU/67mJonbeXpzfxgi8K7HIG2a8Xpjd0gOuCk/Pu9EI=",
|
| 65 |
-
"ops/attn/backends/__init__.py": "
|
| 66 |
-
"ops/attn/
|
| 67 |
-
"ops/attn/
|
| 68 |
-
"ops/attn/
|
|
|
|
|
|
|
| 69 |
"ops/attnres/__init__.py": "/ljBk1VNFjDa9XABPXqIiQ05vUdzRV6Dbx/KkQihrWs=",
|
| 70 |
-
"ops/attnres/
|
|
|
|
|
|
|
| 71 |
"ops/attnres/naive.py": "nV4WPz/vfRwfRsIzF7pKV95fEx2dQP4BrrPoQCh0a0M=",
|
| 72 |
-
"ops/backends/__init__.py": "3DU4e6t7dmPuZLlHjPnt4q/MAtDXtaMmAcSY4ycyytY=",
|
| 73 |
"ops/based/__init__.py": "qdBLUigpgjQaIN3HTtq57uxoqAaBnQkZbFiEIf18Rvk=",
|
| 74 |
-
"ops/based/fused_chunk.py": "
|
| 75 |
"ops/based/naive.py": "YWIFSLeslp2ruyQDz/uCr5V4ao2cyRyeQH1wiVLMB8U=",
|
| 76 |
-
"ops/based/parallel.py": "
|
| 77 |
"ops/comba/__init__.py": "FBKonbvPPFHY7an2Auh1sXVJLbcgwX8aAD5fxi2oecY=",
|
| 78 |
-
"ops/comba/chunk.py": "
|
| 79 |
-
"ops/comba/fused_recurrent.py": "
|
| 80 |
"ops/comba/naive.py": "QH967c5rxlSSDs6J6jRtLjZ3iLiwgAYgY9+0m9rgD18=",
|
| 81 |
-
"ops/comba/utils.py": "
|
| 82 |
-
"ops/comba/wy_fast.py": "
|
| 83 |
-
"ops/common/__init__.py": "
|
| 84 |
-
"ops/common/backends/__init__.py": "
|
| 85 |
-
"ops/common/backends/intracard.py": "
|
| 86 |
-
"ops/common/backends/tilelang/__init__.py": "
|
| 87 |
-
"ops/common/backends/tilelang/chunk_bwd.py": "
|
| 88 |
-
"ops/common/
|
| 89 |
-
"ops/common/
|
| 90 |
-
"ops/common/
|
| 91 |
-
"ops/common/
|
| 92 |
-
"ops/common/
|
| 93 |
-
"ops/common/
|
| 94 |
-
"ops/common/
|
| 95 |
-
"ops/common/
|
| 96 |
-
"ops/common/
|
| 97 |
-
"ops/common/
|
| 98 |
-
"ops/common/gate.py": "ExEV4w/h/y44Qb6L1cwOFEsMutGjs/t338KimPVjeHM=",
|
| 99 |
-
"ops/common/intracard_cp.py": "R+wNrYC2m0gUn0jr5CpsxpCIVRCRkRnFXjBus9XbDE8=",
|
| 100 |
"ops/cp/__init__.py": "uud2WkodJvH5U5DjBa5oSLJtZ1G8O4D4XEuspXyC9lA=",
|
| 101 |
-
"ops/cp/chunk_delta_h.py": "+
|
| 102 |
"ops/cp/comm.py": "lqyQDwmK19vowTtGJGO+6SEn/neFFE0G8xFvlxLOmb0=",
|
| 103 |
-
"ops/cp/context.py": "
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 104 |
"ops/delta_rule/__init__.py": "1gIkBajhtbVwuJOgPQ+FYYdq4tYgNgib+veOnont+N4=",
|
| 105 |
-
"ops/delta_rule/chunk.py": "
|
| 106 |
"ops/delta_rule/fused_chunk.py": "2NiUBRAl98YgRVGr2uzYJV22pQW3WNOe6euTX1Mdqyw=",
|
| 107 |
-
"ops/delta_rule/fused_recurrent.py": "
|
| 108 |
"ops/delta_rule/naive.py": "IK4DL04IAZtCmMyfzyw5fYcfqsD9HxgCQ9n2makZKWg=",
|
| 109 |
-
"ops/delta_rule/parallel.py": "
|
| 110 |
-
"ops/delta_rule/wy_fast.py": "
|
| 111 |
"ops/deltaformer/__init__.py": "51ZmNFoHy3P0lVn/2EHKu1QS2BMC6h+hnAwSIr9szYg=",
|
| 112 |
"ops/deltaformer/invcum.py": "ren181AxlHBv2MoZIHmSGMmJ0sW6HDb3t8fqG7gDELU=",
|
| 113 |
-
"ops/deltaformer/naive.py": "
|
| 114 |
-
"ops/deltaformer/parallel.py": "
|
| 115 |
"ops/dsa/__init__.py": "ZNyws889LPBiY8gwB5zTs2vQwJYV8bX5jg6Cldkkq9s=",
|
| 116 |
-
"ops/dsa/naive.py": "
|
| 117 |
"ops/forgetting_attn/__init__.py": "A6ozg9zdEsz4lgUAXqEIUY8CeNp+5IZqYKOpChpj/A4=",
|
| 118 |
-
"ops/forgetting_attn/naive.py": "
|
| 119 |
-
"ops/forgetting_attn/parallel.py": "
|
| 120 |
"ops/gated_delta_product/__init__.py": "0MAzYdxP0ODZjN4WNQ+3HLwigokyfMv15rXUpTX+qnw=",
|
| 121 |
-
"ops/gated_delta_product/chunk.py": "
|
| 122 |
-
"ops/gated_delta_product/chunk_deltaproduct_h.py": "
|
| 123 |
-
"ops/gated_delta_product/chunk_deltaproduct_o.py": "
|
| 124 |
"ops/gated_delta_product/chunk_ref.py": "R1dHdPy4rU+lTQQKodAn9h2xPLxmwI2z0T6pRvh8Llo=",
|
| 125 |
-
"ops/gated_delta_product/naive.py": "
|
| 126 |
"ops/gated_delta_rule/__init__.py": "Xt0hhHr3CECyZDmBIZakdufk3bvvIa/V/iBmpkYwpnw=",
|
| 127 |
-
"ops/gated_delta_rule/
|
| 128 |
-
"ops/gated_delta_rule/
|
| 129 |
-
"ops/gated_delta_rule/
|
| 130 |
-
"ops/gated_delta_rule/
|
|
|
|
|
|
|
| 131 |
"ops/gated_delta_rule/naive.py": "0c8XmSNJ/T6Ur5mbIuPTqBvkotGIHOW3CjRXJXFm4Ms=",
|
| 132 |
-
"ops/gated_delta_rule/wy_fast.py": "
|
| 133 |
"ops/gated_oja_rule/__init__.py": "oShC/cL0jMy+xWR7YBV9QxkAdxt1xasXDCypGAU6Hgo=",
|
| 134 |
"ops/gated_oja_rule/chunk.py": "lq+5BXEaJLfL4dqqcJb4TmtyF9OrP9Wh+JpRfpdzd2s=",
|
| 135 |
-
"ops/gated_oja_rule/chunk_h.py": "
|
| 136 |
-
"ops/gated_oja_rule/chunk_kkt.py": "
|
| 137 |
-
"ops/gated_oja_rule/chunk_o.py": "
|
| 138 |
-
"ops/gated_oja_rule/fused_recurrent.py": "
|
| 139 |
-
"ops/gated_oja_rule/wy_fast.py": "
|
| 140 |
"ops/gdn2/__init__.py": "xiEsgvVEfHhKcurQqL7ZKGGzEBW2BtGAylE9vxoNmAk=",
|
| 141 |
-
"ops/gdn2/
|
| 142 |
-
"ops/gdn2/
|
| 143 |
-
"ops/gdn2/
|
| 144 |
-
"ops/gdn2/
|
| 145 |
-
"ops/gdn2/
|
| 146 |
-
"ops/gdn2/
|
|
|
|
| 147 |
"ops/gdn2/naive.py": "amWAVAHrMA34W2KXYRoN0VjdGDQjzyvNXg8Ozd4+nno=",
|
| 148 |
-
"ops/gdn2/wy_fast.py": "
|
| 149 |
"ops/generalized_delta_rule/__init__.py": "cn6rKWEDrxWw428Dk6EEy4Y7nyWHpc8rtR+EbRO9ndA=",
|
| 150 |
"ops/generalized_delta_rule/dplr/__init__.py": "F8TbaiZeRKjbKhlI4XYopNd4bfzV10feNO06i32h2Vo=",
|
| 151 |
-
"ops/generalized_delta_rule/dplr/
|
| 152 |
-
"ops/generalized_delta_rule/dplr/
|
| 153 |
-
"ops/generalized_delta_rule/dplr/
|
| 154 |
-
"ops/generalized_delta_rule/dplr/
|
| 155 |
-
"ops/generalized_delta_rule/dplr/
|
| 156 |
-
"ops/generalized_delta_rule/dplr/
|
| 157 |
-
"ops/generalized_delta_rule/dplr/
|
| 158 |
-
"ops/generalized_delta_rule/dplr/
|
|
|
|
| 159 |
"ops/generalized_delta_rule/dplr/naive.py": "4flLSZUtwaq5S/PH+fu04rzOM2+USdRX6Ofte4lanE8=",
|
| 160 |
-
"ops/generalized_delta_rule/dplr/wy_fast_bwd.py": "
|
| 161 |
-
"ops/generalized_delta_rule/dplr/wy_fast_fwd.py": "
|
| 162 |
"ops/generalized_delta_rule/iplr/__init__.py": "6Vg8MTc+Byrnmx3HJz2yySi9nk2kyKCSg7aL4CMJ+GA=",
|
| 163 |
-
"ops/generalized_delta_rule/iplr/chunk.py": "
|
| 164 |
-
"ops/generalized_delta_rule/iplr/fused_recurrent.py": "
|
| 165 |
"ops/generalized_delta_rule/iplr/naive.py": "YotccLOueXwBcQys4ICmFAysSrX8fj9eRasXIpmpRMo=",
|
| 166 |
-
"ops/generalized_delta_rule/iplr/wy_fast.py": "
|
| 167 |
"ops/gla/__init__.py": "PTUqqQlC4cXrhRhG/KRx+7X3m9WJKxGyzrIB/WJEXSo=",
|
| 168 |
-
"ops/gla/
|
|
|
|
| 169 |
"ops/gla/fused_chunk.py": "OjzKcjSQujVQ+Q+d1Lmg4tsTzZaK6xWs8AGuplRn5zo=",
|
| 170 |
-
"ops/gla/fused_recurrent.py": "
|
| 171 |
"ops/gla/naive.py": "rEuH5bEAieya1CTvtZbebVFo2J5LdOX1ztL1WiDkZB0=",
|
| 172 |
"ops/gsa/__init__.py": "9uygbV6orNtaTkZl9Hz+aAp7EvT6RuffawfeFtuUNEE=",
|
| 173 |
-
"ops/gsa/chunk.py": "
|
| 174 |
-
"ops/gsa/
|
| 175 |
-
"ops/gsa/
|
|
|
|
|
|
|
|
|
|
| 176 |
"ops/hgrn/__init__.py": "69DMv7FQYvobQTXqOFtu7muAt1k1k9nvsFXcMAmjQmg=",
|
| 177 |
-
"ops/hgrn/chunk.py": "
|
| 178 |
-
"ops/hgrn/fused_recurrent.py": "
|
| 179 |
"ops/hgrn/naive.py": "XKo+5zJ+G4elkgK5ARsoXm5WYkG1QidTKNIuPT4k588=",
|
| 180 |
-
"ops/kda/__init__.py": "
|
| 181 |
-
"ops/kda/backends/__init__.py": "
|
| 182 |
-
"ops/kda/backends/
|
| 183 |
-
"ops/kda/
|
| 184 |
-
"ops/kda/
|
| 185 |
-
"ops/kda/
|
| 186 |
-
"ops/kda/
|
| 187 |
-
"ops/kda/
|
| 188 |
-
"ops/kda/
|
| 189 |
-
"ops/kda/
|
| 190 |
-
"ops/kda/fused_recurrent.py": "r6ZJMiLVmCRLpbYXS25mIX58KU2yKtDJqGwwHTXY0MY=",
|
| 191 |
-
"ops/kda/gate.py": "5056ezuomW2CNvPE04MraGJtf0gHvGqicxin1H0DICg=",
|
| 192 |
"ops/kda/naive.py": "YKMihdS2cGj/YztIu+irMQKAZtJPANJ+EhmaiPxz8BY=",
|
| 193 |
-
"ops/kda/wy_fast.py": "
|
|
|
|
|
|
|
|
|
|
| 194 |
"ops/lightning_attn/__init__.py": "FPVVYNLjfO3GJQYIp+4HCQ4MdJtF8UZx5yktWDIatFA=",
|
| 195 |
-
"ops/lightning_attn/chunk.py": "
|
| 196 |
-
"ops/lightning_attn/fused_recurrent.py": "
|
| 197 |
"ops/linear_attn/__init__.py": "3OeyduLmyi1manyo7FQz1ZLSoLgEXAKbHKn1uqDcK90=",
|
| 198 |
"ops/linear_attn/chunk.py": "5xqgOnPPA7nGPt/Rda4wOxSljFTD3Izw63VpuDLJNd8=",
|
| 199 |
"ops/linear_attn/fused_chunk.py": "MD6FycgZSdn8jV88UDvxpioPAw6hCxvsSq49qNIKpmo=",
|
| 200 |
"ops/linear_attn/fused_recurrent.py": "jUZ5gPuN2VngqbebHbN0lrIAOiZOYkxIku+C3Eh/9Vw=",
|
| 201 |
"ops/linear_attn/naive.py": "46BX2exbemO1c8XXVhmkz2m6H1ywTmrvT4/odStEA8g=",
|
| 202 |
-
"ops/linear_attn/utils.py": "
|
| 203 |
"ops/log_linear_attn/__init__.py": "qsAhfXSfoQBDmP6Li6+CjNd9ysMDGjcbYLonvcZcrjU=",
|
| 204 |
-
"ops/log_linear_attn/chunk.py": "
|
| 205 |
-
"ops/log_linear_attn/naive.py": "
|
| 206 |
"ops/mesa_net/__init__.py": "32w1RDjxggXJ9JobAR01dDnN2UZSG2Fui7qePyQT2J4=",
|
| 207 |
-
"ops/mesa_net/chunk.py": "
|
| 208 |
-
"ops/mesa_net/chunk_cg_solver_bwd.py": "
|
| 209 |
-
"ops/mesa_net/chunk_cg_solver_fwd.py": "
|
| 210 |
-
"ops/mesa_net/chunk_h_fwd.py": "
|
| 211 |
-
"ops/mesa_net/chunk_h_kk_intra_bwd.py": "
|
| 212 |
-
"ops/mesa_net/chunk_h_kv_intra_bwd.py": "
|
| 213 |
-
"ops/mesa_net/chunk_h_kv_intra_bwd_separate.py": "
|
| 214 |
-
"ops/mesa_net/decoding_one_step.py": "
|
| 215 |
"ops/mesa_net/naive.py": "zv3jT+71UegNb0JyIKnPv8OddyzHu4weEETtt0nJvzA=",
|
| 216 |
"ops/moba/__init__.py": "P7ARNbLLMsmTtxcxPk09NPmjcvHGwWCmooXPYvT6ANk=",
|
| 217 |
-
"ops/moba/parallel.py": "
|
|
|
|
|
|
|
|
|
|
|
|
|
| 218 |
"ops/nsa/__init__.py": "6Mw2zDl4Z74QXVjME1d88PMSKTSO/AYUa00lW/IK+eI=",
|
| 219 |
-
"ops/nsa/compression.py": "
|
| 220 |
-
"ops/nsa/naive.py": "
|
| 221 |
-
"ops/nsa/parallel.py": "
|
| 222 |
"ops/nsa/utils.py": "lbhybLC0CqXTn6liY8d1sQfTdZ2Gl+++Y5Go53OX4xE=",
|
| 223 |
"ops/parallax/__init__.py": "g2pTOybF7cyoyaMAku1gpjV5MBY6s/Ll1X2NT6/w/YM=",
|
| 224 |
-
"ops/parallax/decode.py": "
|
| 225 |
-
"ops/parallax/naive.py": "
|
| 226 |
-
"ops/parallax/parallel.py": "
|
| 227 |
"ops/path_attn/__init__.py": "eyvdV5LkkxztzDTDYAl862vhXITUOcMtF6D8n6n0O/E=",
|
| 228 |
-
"ops/path_attn/cumprod_householder_bwd.py": "
|
| 229 |
-
"ops/path_attn/cumprod_householder_fwd.py": "
|
| 230 |
-
"ops/path_attn/intra_chunk_preprocess_bwd.py": "
|
| 231 |
-
"ops/path_attn/intra_chunk_preprocess_bwd_prepare.py": "
|
| 232 |
-
"ops/path_attn/intra_chunk_preprocess_fwd.py": "
|
| 233 |
"ops/path_attn/naive.py": "4QsKiZUcF0q4IJbrku4Xu/IR3YBg+n6Epio7FAOW9lk=",
|
| 234 |
"ops/path_attn/parallel.py": "V1c/T2VKbs8MgNJ0AT2JA5ULpx49aLb5maoxizAbVjk=",
|
| 235 |
-
"ops/path_attn/parallel_path_bwd_inter_dkv.py": "
|
| 236 |
-
"ops/path_attn/parallel_path_bwd_inter_dqh.py": "
|
| 237 |
-
"ops/path_attn/parallel_path_bwd_intra.py": "+
|
| 238 |
-
"ops/path_attn/parallel_path_fwd.py": "
|
| 239 |
-
"ops/path_attn/prepare_k_cache.py": "
|
| 240 |
-
"ops/path_attn/transform_q.py": "
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 241 |
"ops/rebased/__init__.py": "pawYkzOJ/mQY5Qj0Ibuq81P3KNgO9Lv6swOxCjlDlGs=",
|
| 242 |
"ops/rebased/naive.py": "XOrMn2Ohd7MDJ7QvP93dPfjv/6prnZW/ozxHtU0KqWQ=",
|
| 243 |
-
"ops/rebased/parallel.py": "
|
| 244 |
"ops/retention/__init__.py": "i6uHA1ndTR6T/fVfooceKo12wyBFGYLe1EAm0Mo/sg0=",
|
| 245 |
-
"ops/retention/chunk.py": "
|
| 246 |
-
"ops/retention/fused_chunk.py": "
|
| 247 |
-
"ops/retention/fused_recurrent.py": "
|
| 248 |
"ops/retention/naive.py": "MG107SmOiRKLTZ8ziqaWN85nbgIPj/GqNJJ7KMt5Tag=",
|
| 249 |
-
"ops/retention/parallel.py": "
|
| 250 |
"ops/rwkv4/__init__.py": "GnWakdtZiQJ0+fTYxqqIyosoPwjH6Yp8P1AbpHIDnts=",
|
| 251 |
-
"ops/rwkv4/fused_recurrent.py": "
|
| 252 |
"ops/rwkv6/__init__.py": "wPYgC6wG+xc4I2vessGhv1EaZ4tL5yuVQVSwi1rEEUk=",
|
| 253 |
-
"ops/rwkv6/
|
|
|
|
| 254 |
"ops/rwkv6/chunk_naive.py": "zyj0Og15jGxNMzmlD9FoEdf/odzu3tqio/jiceVMNk4=",
|
| 255 |
-
"ops/rwkv6/fused_recurrent.py": "
|
| 256 |
"ops/rwkv6/recurrent_naive.py": "/lCgua1vSaJDqA4tOWWUaVxol5Axi3cOcjI+mJj7OAM=",
|
| 257 |
"ops/rwkv7/__init__.py": "dPKBISLNnwlKb+xp/8ejsc2peC9gKQ3NedtMT5wQ1sE=",
|
| 258 |
-
"ops/rwkv7/channel_mixing.py": "
|
| 259 |
-
"ops/rwkv7/chunk.py": "
|
| 260 |
-
"ops/rwkv7/fused_addcmul.py": "
|
| 261 |
-
"ops/rwkv7/fused_k_update.py": "
|
| 262 |
-
"ops/rwkv7/fused_recurrent.py": "
|
| 263 |
-
"ops/rwkv7/gate_output_correction.py": "
|
| 264 |
-
"ops/simple_gla/__init__.py": "
|
| 265 |
-
"ops/simple_gla/
|
| 266 |
-
"ops/simple_gla/
|
| 267 |
-
"ops/simple_gla/
|
|
|
|
| 268 |
"ops/simple_gla/naive.py": "g3fAN++vd0aWvZcdOW7Y0boMYcs2mOld8kePWRbl2R0=",
|
| 269 |
-
"ops/simple_gla/parallel.py": "
|
|
|
|
|
|
|
|
|
|
| 270 |
"ops/titans/__init__.py": "4t9OK1aYdW03I+sUlfUjj3ALTez1M/XFD/H6KzeZtGc=",
|
| 271 |
"ops/titans/log_impl.py": "Y5tMWJgtVE+GX394DdxQHd6Yirrg3sLx6sinMdQvkAE=",
|
| 272 |
-
"ops/titans/naive.py": "
|
| 273 |
"ops/ttt/__init__.py": "cFaLRxAWRsKjcmXh01bJbh5U59ZaFaM7DwYgm/KBAbo=",
|
| 274 |
-
"ops/ttt/chunk.py": "
|
| 275 |
-
"ops/ttt/fused_chunk.py": "
|
| 276 |
-
"ops/ttt/naive.py": "
|
| 277 |
-
"ops/utils/__init__.py": "
|
| 278 |
-
"ops/utils/
|
| 279 |
-
"ops/utils/backends/triton_ascend/__init__.py": "rpIPSLMvhpuf3aqxxDUGQrrq6dKKF5Nk2qsJl+H34Lc=",
|
| 280 |
-
"ops/utils/backends/triton_ascend/cumsum.py": "AOxEn57vvwiNwOaDcVK3KbP+n5IUGrsbUWkG+kkukBg=",
|
| 281 |
-
"ops/utils/cache.py": "pksJ/9P1Gu1UetclWd7pTLmur9Kl8CxsjmCm4CAUepw=",
|
| 282 |
"ops/utils/constant.py": "uVK9zwOd7kM/DPSQk8cllx5nkYeK0K/KZVyCu0ZFdPg=",
|
| 283 |
-
"ops/utils/csr.py": "
|
| 284 |
-
"ops/utils/cumsum.py": "
|
| 285 |
-
"ops/utils/
|
| 286 |
-
"ops/utils/
|
| 287 |
-
"ops/utils/
|
| 288 |
-
"ops/utils/
|
| 289 |
-
"ops/utils/
|
| 290 |
-
"ops/utils/
|
| 291 |
-
"ops/utils/
|
| 292 |
-
"ops/utils/
|
| 293 |
-
"ops/utils/
|
| 294 |
-
"ops/utils/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 295 |
"ops/wall_attn/__init__.py": "r/FbDGjGO8WK1DaMbl9axWHpENUa3pzSc0v9qviHJ6I=",
|
| 296 |
-
"ops/wall_attn/decode.py": "
|
| 297 |
"ops/wall_attn/naive.py": "9YKwBSvQ9imy229T5KMYKpuVNb+xEzhXsXdMemRWqjQ=",
|
| 298 |
-
"ops/wall_attn/parallel.py": "
|
| 299 |
-
"symbols.json": "
|
| 300 |
-
"utils/__init__.py": "
|
| 301 |
-
"utils/
|
| 302 |
-
"utils/
|
| 303 |
-
"utils/
|
| 304 |
-
"utils/
|
| 305 |
-
"utils/
|
| 306 |
-
"utils/ascend_ub_manager.py": "TcjVL6L7YiNwsa7YZ4+9KrIPQ2RmG7PJCfmXYc24uEc=",
|
| 307 |
-
"utils/layers.py": "afB10gGysmmVfVRlPnduPpuvcdAeDAstmqPC0sYJbRw="
|
| 308 |
}
|
| 309 |
},
|
| 310 |
"provenance": {
|
|
@@ -314,7 +355,7 @@
|
|
| 314 |
"dirty": false
|
| 315 |
},
|
| 316 |
"kernel": {
|
| 317 |
-
"commit": "
|
| 318 |
"dirty": false
|
| 319 |
}
|
| 320 |
}
|
|
|
|
| 1 |
{
|
| 2 |
"name": "fla",
|
| 3 |
+
"id": "_fla_cuda_faa8674",
|
| 4 |
+
"version": 2,
|
| 5 |
"kernels-minver": "0.14.0",
|
| 6 |
"license": "MIT",
|
| 7 |
"python-depends": [
|
|
|
|
| 14 |
"digest": {
|
| 15 |
"algorithm": "sha256",
|
| 16 |
"files": {
|
| 17 |
+
"__init__.py": "eSkze5EKF+DhheKdXmGOOQPa6oJCFDY0fw3vg7WX3mU=",
|
| 18 |
+
"_ops.py": "q78tXrH/5M5hfjOclPcmC6NXw+I2de7vH6gfnXW225o=",
|
| 19 |
+
"backends.py": "h+9RflmubYjIEs0Fqhadj8SzFXHr+ghgXBmqn5Tm9v4=",
|
| 20 |
+
"layers.py": "MogF8nJKBsgqJjVXLjVFJHBMakhJCkK2of1ykPWF0yA=",
|
| 21 |
+
"modules/__init__.py": "rq5MxYJ+DgZLmrKdBb/PB1Q6PcuZ+rP0btubKE7uMdc=",
|
| 22 |
+
"modules/activations/__init__.py": "kjYo6ny71n6YPTd5Y6FrBPehfjS1Tl6rZh1QYcflZ9k=",
|
| 23 |
+
"modules/activations/ops.py": "toY9DY+ZmrAgJL4e8QOVKpYuw7QSYLUTxxCU3m+8ZaQ=",
|
| 24 |
+
"modules/causal_conv1d/__init__.py": "Z439ju3G3EQsurHFMVv0MQkKktuFw8/drnyp8oflj0Q=",
|
| 25 |
+
"modules/causal_conv1d/backends/__init__.py": "ZxTK7vZktZ7TBQB/5oiJr+oIypQU1cgkbn/ybwJl450=",
|
| 26 |
+
"modules/causal_conv1d/backends/cuda/__init__.py": "erS68kB9gBCaE0rX1ES+sKr8FCKE9pH/EB3rPWCrYCs=",
|
| 27 |
+
"modules/causal_conv1d/backends/cuda/cp.py": "s1x3wm+BuGbY0uAVGw+cLUBOtuixmZH80EFiyYLEIvQ=",
|
| 28 |
+
"modules/causal_conv1d/backends/cuda/ops.py": "73qKlHa75wF92ugakgiqbNYthaEDltGtAqz7ClVMsu4=",
|
| 29 |
+
"modules/causal_conv1d/backends/gluon.py": "KtMSmMOGSiioJGcWT237Uj27ryoZrsaNMx8BoOqAf9U=",
|
| 30 |
+
"modules/causal_conv1d/cp.py": "UGe4T/utfJ/mjhPM1WDnCJL8q/I8c4rpBQUDbRFjXyg=",
|
| 31 |
+
"modules/causal_conv1d/ops.py": "vEvfb5BXlVWOqXzzf5Rt0WcpEbjnfw/fYnOKxi91NmY=",
|
| 32 |
+
"modules/feature_map.py": "1+D3QXgIAEspjPM3aZ4ugVRSPeYEWJ+eqN3djUyQofk=",
|
| 33 |
+
"modules/fused_bitlinear.py": "cUFUweFZFmJS/Zl+8Ex3Kit9EHJJkcWabyH85wuwtDg=",
|
| 34 |
+
"modules/fused_cross_entropy/__init__.py": "nLRzNtHqTxjxgQT0EIs9RzmwfAu6baobksBU/Znd7rA=",
|
| 35 |
+
"modules/fused_cross_entropy/gluon.py": "qO/HNquDhMHIqN+59VlJcC37FwcqDaSoIz3mZMoH2Po=",
|
| 36 |
+
"modules/fused_cross_entropy/ops.py": "EwWAwIVHIOFrB1QPh335jjlvDYfVPEN1K9FjVtGxFWk=",
|
| 37 |
+
"modules/fused_kl_div/__init__.py": "L6dw1Iru9kTpqpwGWP81uMBUCf719A5eF+7awXroNYs=",
|
| 38 |
+
"modules/fused_kl_div/ops.py": "BDp6i7k/mDtwCi57T/ZKCUFS0lJpVm0vktiGH76bTy4=",
|
| 39 |
+
"modules/fused_linear_cross_entropy/__init__.py": "h0f6nBT3ezaBQExjxH+0ZpIfV/+jzp0cHNfvTkLQXYw=",
|
| 40 |
+
"modules/fused_linear_cross_entropy/ops.py": "qzLHd+ePGPNxynsHJiZXuQ5fGxTbhOR/q/n3ACAEZgs=",
|
| 41 |
+
"modules/grpo/__init__.py": "/+3ocSnRFVx59pEfhKGRhjw5SQctEOle3KwGSHUmhrk=",
|
| 42 |
+
"modules/grpo/ops.py": "58V3OfIwt4dBXMCvqaiBH6om10HKECwVeSHJ0h+XuzE=",
|
| 43 |
+
"modules/l2warp.py": "Tq8EvtlI+6mDqVhjd5tYYZgzCEuBCL0LJWWNFdKjjRw=",
|
| 44 |
+
"modules/long_conv.py": "EdjKO2tZyPuJVu7uvCXQTHINGySbcUb7lu6PK5kiKnE=",
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 45 |
"modules/mlp.py": "q09Zw5Bttqq27hnlybbQ9ncr0jSw1UCrJH2Ewh9roV4=",
|
| 46 |
+
"modules/norm/__init__.py": "pjZst4x0d6Cupu9pETPPzEv/YIZOg2s5a2IOEwpAbZA=",
|
| 47 |
+
"modules/norm/fused_norm_gate.py": "Ex+3MGO0fgNz34LBJPxE77oL9JTT5Kw9TEUG6YUNAqs=",
|
| 48 |
+
"modules/norm/l2norm.py": "eSt9ICshJk489wkyGAPtmFqv678u6Iqj02HXtB+BthQ=",
|
| 49 |
+
"modules/norm/layernorm.py": "xqeuqNBIH79m7UcrlPlPjAZCzTc7vmfNsqNFBLH8xXs=",
|
| 50 |
+
"modules/norm/layernorm_gated.py": "6bzsO2HBwOU32pUuiiFwDsobrMNhABGPJguGCGk7VTg=",
|
| 51 |
+
"modules/norm/layernorm_quant.py": "BZHD/kPfNszPl0JsW9j+ZUOnHQOH2LwdaRNj9pv/o/A=",
|
| 52 |
+
"modules/parallel.py": "so6JnuagTE/nZBIjhNs/mwhcZtAbRr+DEwDCT3yLB30=",
|
| 53 |
+
"modules/rotary/__init__.py": "Vijv0n40cGYaaX/x3M1CsnLG6gjVxsmjTflZLxzNAq4=",
|
| 54 |
+
"modules/rotary/ops.py": "EGgH28oKJM5lcMXl/5tTD+j4Yxfq/L7n8s/jZA7rAUk=",
|
| 55 |
+
"modules/token_shift.py": "SiiXroq05nOI+fYGTpMxP/J7M3VnGonWr6eF6bWspI8=",
|
| 56 |
+
"modules/token_shift_cp.py": "q0OchsRLmUl6mSEdDgtJUpT5Y3HA4wrpUiSWHY3Hcyg=",
|
| 57 |
+
"ops/__init__.py": "c1AozqIP1VhM9A/lV0mO/nrHrTkbgaNn2aSyM6y0CCc=",
|
| 58 |
"ops/abc/__init__.py": "WwLiIkYi3xJ5RiG/bOCNNRaeeqmMuIPT6n1g23qfpDg=",
|
| 59 |
+
"ops/abc/chunk.py": "UiMPJJgp/whOIdGxHx9ZkfKgbM8FCMEb9rd4oXXQ3cQ=",
|
| 60 |
"ops/abc/naive.py": "AZ3uz9eDvycW3gTwZuv9J4k86KndfQMZiLBFyPmzsLw=",
|
| 61 |
+
"ops/atk/__init__.py": "7D6lvGGxM+O5oAsRP2Rs9x9fFh48dBE4RuanHM0lCsM=",
|
| 62 |
+
"ops/atk/backends/__init__.py": "k/wccBdiH8LsLHjs/LB5l6utDxQ1xwxehzK1wC1Cdl0=",
|
| 63 |
+
"ops/atk/chunk_atk_bwd.py": "KP9Ek4fmTbKxre3TlqhoC3EzkdnI0DbVw55/gK8cndY=",
|
| 64 |
+
"ops/atk/chunk_atk_fwd.py": "BRYqeWa2M0n2gvkNlFfIenhyr0hcMP3BcoeiojEqUQg=",
|
| 65 |
"ops/attn/__init__.py": "gU/67mJonbeXpzfxgi8K7HIG2a8Xpjd0gOuCk/Pu9EI=",
|
| 66 |
+
"ops/attn/backends/__init__.py": "YSU1FRHkTNYuPlHp5Ky5ZC7OgD0Ul32qARLiXPf6qoo=",
|
| 67 |
+
"ops/attn/backends/tilelang/__init__.py": "VJdfMdLIoy9BWt49a6z0mnyGiFtIBmzHFdfHRjiBYrI=",
|
| 68 |
+
"ops/attn/backends/tilelang/parallel.py": "MvrzoFaTR/z+yljm5MA1Piq5CFIT36ku1bMVYchAQrU=",
|
| 69 |
+
"ops/attn/decoding.py": "J1up9AtGqemUJel+bHCbY5tXQBn/p/dy9K0nwlV1EMM=",
|
| 70 |
+
"ops/attn/naive.py": "Ns1vl3PBVEcW7+4kwW87ATCccIcghu24uWr5fDTS0s4=",
|
| 71 |
+
"ops/attn/parallel.py": "bNsWwVHS7LNWtcpZ6F2aWLglgCVKcIjIA5P4puUDYMc=",
|
| 72 |
"ops/attnres/__init__.py": "/ljBk1VNFjDa9XABPXqIiQ05vUdzRV6Dbx/KkQihrWs=",
|
| 73 |
+
"ops/attnres/backends/__init__.py": "R08rRiTtJKcbPZBFsllcEpnbT0bSzQk5NGRgn779j5g=",
|
| 74 |
+
"ops/attnres/backends/gluon.py": "3TwxEZvH8NccliN4Cu4PzsYYMiqObQwIqYOaKmmdpiI=",
|
| 75 |
+
"ops/attnres/fused.py": "RxdxfbEKzeZ0rvieg3/4nbnV+011tb9ZtVEOT46mnfc=",
|
| 76 |
"ops/attnres/naive.py": "nV4WPz/vfRwfRsIzF7pKV95fEx2dQP4BrrPoQCh0a0M=",
|
|
|
|
| 77 |
"ops/based/__init__.py": "qdBLUigpgjQaIN3HTtq57uxoqAaBnQkZbFiEIf18Rvk=",
|
| 78 |
+
"ops/based/fused_chunk.py": "gBng4smV8X5eHn0pgo677bsu8kvOZ+DNEkJbvegBxZo=",
|
| 79 |
"ops/based/naive.py": "YWIFSLeslp2ruyQDz/uCr5V4ao2cyRyeQH1wiVLMB8U=",
|
| 80 |
+
"ops/based/parallel.py": "daBATK+vtrog3XYFx2WkTfyg0QPH0gGb/6zlaTZCeIs=",
|
| 81 |
"ops/comba/__init__.py": "FBKonbvPPFHY7an2Auh1sXVJLbcgwX8aAD5fxi2oecY=",
|
| 82 |
+
"ops/comba/chunk.py": "dtxGTXfgVY0c8TMq6uSBDUBjaP9tNk5WsnScEyVDVpI=",
|
| 83 |
+
"ops/comba/fused_recurrent.py": "sVNBWn5bq7PI7QIpCGbDMGBfl0CMzDzv767eR+5jCiw=",
|
| 84 |
"ops/comba/naive.py": "QH967c5rxlSSDs6J6jRtLjZ3iLiwgAYgY9+0m9rgD18=",
|
| 85 |
+
"ops/comba/utils.py": "1nCCwG8f9KZlupZOwb1M3zH8MkUKILB44GaLFxI8cUw=",
|
| 86 |
+
"ops/comba/wy_fast.py": "9cijtR5+g55508HeHN0nedcRcBu5doCZad/6b+r+NsM=",
|
| 87 |
+
"ops/common/__init__.py": "yN9sU6JLmt6oHmOBursxys8xjykn/RubQlhzf+F4hfo=",
|
| 88 |
+
"ops/common/backends/__init__.py": "51Y0UR2Ro+8SU+rWoHNKpGNcBVC+F0CjQ4KjKMHA9cg=",
|
| 89 |
+
"ops/common/backends/intracard.py": "mExR+X9YFuNXkoM3x5t/78kdzUk/ypZhBq+0XWmEZfc=",
|
| 90 |
+
"ops/common/backends/tilelang/__init__.py": "N4GWBK2DAUoBSuxrTKD4b1Qsb1BtGHQZqBpXy57WhF4=",
|
| 91 |
+
"ops/common/backends/tilelang/chunk_bwd.py": "v6bPgT1lCK1MBdsarkfulW9rEQHEVYcZdyWh7k4F16k=",
|
| 92 |
+
"ops/common/chunk_delta_h.py": "bwziSs86L78fXsQNPMnXOSCVL1h/g80uWd3dvwtZuV0=",
|
| 93 |
+
"ops/common/chunk_h.py": "nR4KBApZUosIPbKg+rOZ/fL1C7vKJqowY6tUJy1pRu8=",
|
| 94 |
+
"ops/common/chunk_h_parallel.py": "vLG7BiBe4WhuB5M8x30rAeqFquGerzwIkRB2V5IXwVw=",
|
| 95 |
+
"ops/common/chunk_h_split.py": "bNGwtZ1QAA/qhJ6mpgDWMcIK/3043cTzyMMKUyFCNpo=",
|
| 96 |
+
"ops/common/chunk_o.py": "gmMl3/PC5JD+VjhlmnbcEivMAB9qsMvjhys6LFg+5r4=",
|
| 97 |
+
"ops/common/chunk_scaled_dot_kkt.py": "IHtve82Yy5FmP3N8Tq4FvCrlmoqzF5+4fjr7rRYi89M=",
|
| 98 |
+
"ops/common/fused_chunk.py": "R5PRqQBs8L+LDM3u15SXusRYnrJiqjYII168tWNbkDQ=",
|
| 99 |
+
"ops/common/fused_recurrent.py": "ZtFhTDcrB4kzHOEnqV4glzLCUf1x6RO14C+rYorz++Q=",
|
| 100 |
+
"ops/common/gate.py": "WOCYhSul4pkQvNUX7Lco3RDFsf4Dt6Qk6UN1f5Rc8WY=",
|
| 101 |
+
"ops/common/intracard_cp.py": "FUJFbWiaKt/APVmS0TQyMrHZEVAaAi6eu/VM4jhBqRk=",
|
|
|
|
|
|
|
| 102 |
"ops/cp/__init__.py": "uud2WkodJvH5U5DjBa5oSLJtZ1G8O4D4XEuspXyC9lA=",
|
| 103 |
+
"ops/cp/chunk_delta_h.py": "OHQD+CubC1RfbNqxsRewZVh/NSNqUMEOuplaNm9FI7U=",
|
| 104 |
"ops/cp/comm.py": "lqyQDwmK19vowTtGJGO+6SEn/neFFE0G8xFvlxLOmb0=",
|
| 105 |
+
"ops/cp/context.py": "VS/fHKQ3dAhML1NkHpjch48iC1KJjE2KTBkL4rVlbF4=",
|
| 106 |
+
"ops/cyfa/__init__.py": "OAx8kAAAHpFVQxe3+SV2psaScEIJ5kbnAcOJkOrWo0s=",
|
| 107 |
+
"ops/cyfa/chunk.py": "QgjD/Bv7TlL0qLd17SLVWFs4xas+w61XQ+Zfq1yoPJ8=",
|
| 108 |
+
"ops/cyfa/fused_recurrent.py": "XWLzv2l5TOjGiEcx46f94VVcErCOOMO0+vDO+dn7GdA=",
|
| 109 |
+
"ops/cyfa/naive.py": "95GVYqF/wXwBfLsMf9x9lwJLiSk9LfPWHQyl1QGOYn8=",
|
| 110 |
+
"ops/cyfa/qk_norm.py": "phhdmmvyB6qRosmZC/ybLBKsb6UjXQj/QFU7gjoYe04=",
|
| 111 |
+
"ops/cyfa/utils.py": "U+R2Biu1tPo5GoIEngh2T1GebIgI1yK6gEDfX8qqNGw=",
|
| 112 |
"ops/delta_rule/__init__.py": "1gIkBajhtbVwuJOgPQ+FYYdq4tYgNgib+veOnont+N4=",
|
| 113 |
+
"ops/delta_rule/chunk.py": "ueCVdrAgOpCxVVb7gDgihDRLQck9dY0dOQB/qdxHxGc=",
|
| 114 |
"ops/delta_rule/fused_chunk.py": "2NiUBRAl98YgRVGr2uzYJV22pQW3WNOe6euTX1Mdqyw=",
|
| 115 |
+
"ops/delta_rule/fused_recurrent.py": "WEg6WYVHkdvmncKPtXfYky4skqIe5whzjrX9rE3PAHo=",
|
| 116 |
"ops/delta_rule/naive.py": "IK4DL04IAZtCmMyfzyw5fYcfqsD9HxgCQ9n2makZKWg=",
|
| 117 |
+
"ops/delta_rule/parallel.py": "wR9GWtXrKRwFP+i1ewrvSuO9OJRq+HwYeAkF2pwlchM=",
|
| 118 |
+
"ops/delta_rule/wy_fast.py": "voSaPCMCS/G8crBpowSqB1KI1lQZZQdNuyRlmDTiGVI=",
|
| 119 |
"ops/deltaformer/__init__.py": "51ZmNFoHy3P0lVn/2EHKu1QS2BMC6h+hnAwSIr9szYg=",
|
| 120 |
"ops/deltaformer/invcum.py": "ren181AxlHBv2MoZIHmSGMmJ0sW6HDb3t8fqG7gDELU=",
|
| 121 |
+
"ops/deltaformer/naive.py": "W78CzYUyuxLY9fEkKghSh2dnjux0NOJ6pAVhIN7M4PU=",
|
| 122 |
+
"ops/deltaformer/parallel.py": "XMKE9sLFJl4UVspOXQxhefztzykDEUp7+S9GyUhmOwo=",
|
| 123 |
"ops/dsa/__init__.py": "ZNyws889LPBiY8gwB5zTs2vQwJYV8bX5jg6Cldkkq9s=",
|
| 124 |
+
"ops/dsa/naive.py": "JKyMUzwK44XrwlKUWfLhU/iK5DlCsXceJuxtXrzaCQ8=",
|
| 125 |
"ops/forgetting_attn/__init__.py": "A6ozg9zdEsz4lgUAXqEIUY8CeNp+5IZqYKOpChpj/A4=",
|
| 126 |
+
"ops/forgetting_attn/naive.py": "rjmhL74ja9e060lOrcRgMpAuwO5xDqBKbXw+YoE26+8=",
|
| 127 |
+
"ops/forgetting_attn/parallel.py": "nm4vnTE92QQIvgF+q80TGjweTw8YFX0tyN4Ip4vE7ls=",
|
| 128 |
"ops/gated_delta_product/__init__.py": "0MAzYdxP0ODZjN4WNQ+3HLwigokyfMv15rXUpTX+qnw=",
|
| 129 |
+
"ops/gated_delta_product/chunk.py": "jbQM/fXoRX/nzNZdSgUB5NBB7DYzhQcabsDpuMUUbHE=",
|
| 130 |
+
"ops/gated_delta_product/chunk_deltaproduct_h.py": "w/+GVM+h+ffj5shd1n/rPqhhwIfccadOiUQPU6slGYs=",
|
| 131 |
+
"ops/gated_delta_product/chunk_deltaproduct_o.py": "HAmJ5oygn3R7gHe7Ur5kWAFf9sV3qtS57ZjML69FU34=",
|
| 132 |
"ops/gated_delta_product/chunk_ref.py": "R1dHdPy4rU+lTQQKodAn9h2xPLxmwI2z0T6pRvh8Llo=",
|
| 133 |
+
"ops/gated_delta_product/naive.py": "bJ1Cc3mljHcAXjc4w1JDyxj+i4hmhCPsoELKrTkyvIM=",
|
| 134 |
"ops/gated_delta_rule/__init__.py": "Xt0hhHr3CECyZDmBIZakdufk3bvvIa/V/iBmpkYwpnw=",
|
| 135 |
+
"ops/gated_delta_rule/backends/__init__.py": "iwpwhvQepjkDHC+SDA2b3SziHFeegB79Oz+pU+TsTl8=",
|
| 136 |
+
"ops/gated_delta_rule/backends/flash_qla.py": "b14UI75g/TZIsJLMQk5j71B4B2+JkmYL24zACdtDcRg=",
|
| 137 |
+
"ops/gated_delta_rule/chunk.py": "FJbbVRckUs3kIRXGbCppJdyOCP6/ThpF16ANRmSuiTk=",
|
| 138 |
+
"ops/gated_delta_rule/chunk_fwd.py": "35ZNk4cZW3CWG33fryWIcXLtJ4WGvQvKNonONIKCvWM=",
|
| 139 |
+
"ops/gated_delta_rule/fused_recurrent.py": "b4i7Wb0iuRjzwlXqmAb6AAZiW2o4hWVv5iDJ5dAuGpY=",
|
| 140 |
+
"ops/gated_delta_rule/gate.py": "qAq4nKirRZtlYtHYYbi/jXC8HZZiRaftCwu0haEgmhg=",
|
| 141 |
"ops/gated_delta_rule/naive.py": "0c8XmSNJ/T6Ur5mbIuPTqBvkotGIHOW3CjRXJXFm4Ms=",
|
| 142 |
+
"ops/gated_delta_rule/wy_fast.py": "IayqzhuCGiM6lbjjWKAi1GU4IvgXnZr++xSNq5ZfSKY=",
|
| 143 |
"ops/gated_oja_rule/__init__.py": "oShC/cL0jMy+xWR7YBV9QxkAdxt1xasXDCypGAU6Hgo=",
|
| 144 |
"ops/gated_oja_rule/chunk.py": "lq+5BXEaJLfL4dqqcJb4TmtyF9OrP9Wh+JpRfpdzd2s=",
|
| 145 |
+
"ops/gated_oja_rule/chunk_h.py": "K6g7OMKN9/uUqboAelMpsu8jCwJ2opTKebyZiAEfIYE=",
|
| 146 |
+
"ops/gated_oja_rule/chunk_kkt.py": "9K2pSMxQ3FkmGgiH3JqbN90nixJymRK/x59ohwZYOKk=",
|
| 147 |
+
"ops/gated_oja_rule/chunk_o.py": "AxQIEqnIrWZQmuniM8gk1h+Ynd6d5saoXeJigp03ORw=",
|
| 148 |
+
"ops/gated_oja_rule/fused_recurrent.py": "iHdQaLJGJSLM8X6fYmOqtVe07o97YvidynXGewNG008=",
|
| 149 |
+
"ops/gated_oja_rule/wy_fast.py": "/+qHRfD2tvWfOfPHa7OMdFWezHLqjFnGJyhiUbF02u4=",
|
| 150 |
"ops/gdn2/__init__.py": "xiEsgvVEfHhKcurQqL7ZKGGzEBW2BtGAylE9vxoNmAk=",
|
| 151 |
+
"ops/gdn2/backends/__init__.py": "d3Zf1qLfl/RHs8eAs1cGjN05HBvbxvoWdMke7s1BatQ=",
|
| 152 |
+
"ops/gdn2/chunk.py": "y4dx8rK1CBrPDQthDgnee9WAdWr3JYL5t+9W1/XKAbA=",
|
| 153 |
+
"ops/gdn2/chunk_bwd.py": "CGaUEbBKHR+yZJH8ILgOGDhbEg8S6i4SaI9hV/uXFow=",
|
| 154 |
+
"ops/gdn2/chunk_fwd.py": "GghmT44Q/8kQ1Jc10sGYeAcaKxmhldjJex2Gr/FSyec=",
|
| 155 |
+
"ops/gdn2/chunk_intra.py": "8wEbCvVZ/OTPPDyo9cu7R0WeRJZrqZqqLOAAFL0c2do=",
|
| 156 |
+
"ops/gdn2/chunk_intra_token_parallel.py": "W+tiIjr7D+nxq/4s1itDolgS7mya+LC3b9iJ1oDpMd8=",
|
| 157 |
+
"ops/gdn2/fused_recurrent.py": "TDAjD9IqdASKQX9FLLfSLFgsdTbDoE4jwnShmBQSpAQ=",
|
| 158 |
"ops/gdn2/naive.py": "amWAVAHrMA34W2KXYRoN0VjdGDQjzyvNXg8Ozd4+nno=",
|
| 159 |
+
"ops/gdn2/wy_fast.py": "N0XZaivjPUDGmWPS8tyR/2tqedUcMtlHpaZRZQgn72M=",
|
| 160 |
"ops/generalized_delta_rule/__init__.py": "cn6rKWEDrxWw428Dk6EEy4Y7nyWHpc8rtR+EbRO9ndA=",
|
| 161 |
"ops/generalized_delta_rule/dplr/__init__.py": "F8TbaiZeRKjbKhlI4XYopNd4bfzV10feNO06i32h2Vo=",
|
| 162 |
+
"ops/generalized_delta_rule/dplr/backends/__init__.py": "VkuoS48+KY513u/s51Qpx/Qp4oSuzcMgoeqzc+9uqWE=",
|
| 163 |
+
"ops/generalized_delta_rule/dplr/chunk.py": "KF/hPswvDmMtN0+Q1OQR9TbpDOrMqAWSs5qPbuBOscw=",
|
| 164 |
+
"ops/generalized_delta_rule/dplr/chunk_A_bwd.py": "Sf4K4R7jzOqgTCo/fLhoT5evBHj03sn1qKuqYZLpt3s=",
|
| 165 |
+
"ops/generalized_delta_rule/dplr/chunk_A_fwd.py": "szc1lBh7LvMrdXft3OQWQ+vklQxDrqjmet3d+69VAr0=",
|
| 166 |
+
"ops/generalized_delta_rule/dplr/chunk_h_bwd.py": "/rB+pwDapn9SM8xqp1x3Ro+N4EuvgIoYhte9f1Wl0Jc=",
|
| 167 |
+
"ops/generalized_delta_rule/dplr/chunk_h_fwd.py": "KXBpSZVK4Qvp/2XTe8TVXQw6M8t06N3AHdlldP1+Yi4=",
|
| 168 |
+
"ops/generalized_delta_rule/dplr/chunk_o_bwd.py": "9NLZBaPZ8nlLSfFbbVpoUz3fM5H/VR9nRajBlY2Nx04=",
|
| 169 |
+
"ops/generalized_delta_rule/dplr/chunk_o_fwd.py": "2155nmxibRXn+jOz2MGsUnkdNhWsaHKFvOjmBAmcIq4=",
|
| 170 |
+
"ops/generalized_delta_rule/dplr/fused_recurrent.py": "QT9BmtI4OVj/Nh6Qo6UM3TYb9W+ZifSWHVnJFGKI4Uc=",
|
| 171 |
"ops/generalized_delta_rule/dplr/naive.py": "4flLSZUtwaq5S/PH+fu04rzOM2+USdRX6Ofte4lanE8=",
|
| 172 |
+
"ops/generalized_delta_rule/dplr/wy_fast_bwd.py": "fcpJQxkNls5tEKkP9fxaSqrGkrdZyNzmruFfGpe7hCY=",
|
| 173 |
+
"ops/generalized_delta_rule/dplr/wy_fast_fwd.py": "aNodADVGx656FWS5f9e02Lb0lrp4syVsW8NR6zYZF1Y=",
|
| 174 |
"ops/generalized_delta_rule/iplr/__init__.py": "6Vg8MTc+Byrnmx3HJz2yySi9nk2kyKCSg7aL4CMJ+GA=",
|
| 175 |
+
"ops/generalized_delta_rule/iplr/chunk.py": "YMAVurj1Jmp97+sWuTlzfUOaCUeKlhQzbSGXTzobwW4=",
|
| 176 |
+
"ops/generalized_delta_rule/iplr/fused_recurrent.py": "u5LKf/1u7v9MSnb3mixwWa6/5h7GdDBJ5CHf35Tv1gQ=",
|
| 177 |
"ops/generalized_delta_rule/iplr/naive.py": "YotccLOueXwBcQys4ICmFAysSrX8fj9eRasXIpmpRMo=",
|
| 178 |
+
"ops/generalized_delta_rule/iplr/wy_fast.py": "hqVfLtmdlhQnlIeU7LrByAxBcNYtVSehVFPZW/o8ZhY=",
|
| 179 |
"ops/gla/__init__.py": "PTUqqQlC4cXrhRhG/KRx+7X3m9WJKxGyzrIB/WJEXSo=",
|
| 180 |
+
"ops/gla/backends/__init__.py": "3LkZ6RPx/+FnCqaj6NQC8FovyO0XKlLVkrKopGEt+nk=",
|
| 181 |
+
"ops/gla/chunk.py": "5xTGVCzeQzxbSf8gg3HdcpBPCqOfMykToxXU1NI/S1g=",
|
| 182 |
"ops/gla/fused_chunk.py": "OjzKcjSQujVQ+Q+d1Lmg4tsTzZaK6xWs8AGuplRn5zo=",
|
| 183 |
+
"ops/gla/fused_recurrent.py": "ToICyjG/Jl9CPbYKh/8XCmd+tC0Wuk+zQRrDczQ1yCE=",
|
| 184 |
"ops/gla/naive.py": "rEuH5bEAieya1CTvtZbebVFo2J5LdOX1ztL1WiDkZB0=",
|
| 185 |
"ops/gsa/__init__.py": "9uygbV6orNtaTkZl9Hz+aAp7EvT6RuffawfeFtuUNEE=",
|
| 186 |
+
"ops/gsa/chunk.py": "lAt7ynwdo/OuOmueHQR05KhPgCO+RtZzpPgQf8pz73Y=",
|
| 187 |
+
"ops/gsa/chunk_bwd.py": "zph8XOxa2WmwkAIUpIuLTjpSubQSp8uNiphJeeW+kfM=",
|
| 188 |
+
"ops/gsa/chunk_fwd.py": "goDc5m91bXe1spiElAX1fM5R04qTQgbbvdM7GSc+rsU=",
|
| 189 |
+
"ops/gsa/fused_recurrent.py": "BOxAXEEw6TwbMVpVLR98bB590Y6CrEOfP7/xFu1Ov3Q=",
|
| 190 |
+
"ops/gsa/gate.py": "+oIWuMo420dfL5QIwk21VCjkohKKmwtmoIEVeBdrk9A=",
|
| 191 |
+
"ops/gsa/naive.py": "8ECW81ylA8gLsR3svJsPYd6pAzW8ELmSMuwZzkCJmeM=",
|
| 192 |
"ops/hgrn/__init__.py": "69DMv7FQYvobQTXqOFtu7muAt1k1k9nvsFXcMAmjQmg=",
|
| 193 |
+
"ops/hgrn/chunk.py": "odEz3XdQ1whBWOhYQfCVvMS+zy6QZ36hb9USuqjwV6w=",
|
| 194 |
+
"ops/hgrn/fused_recurrent.py": "SddIcmnP1KUcGWTk2rJGtPEoM5CnuV+zzMOUmK4pc98=",
|
| 195 |
"ops/hgrn/naive.py": "XKo+5zJ+G4elkgK5ARsoXm5WYkG1QidTKNIuPT4k588=",
|
| 196 |
+
"ops/kda/__init__.py": "OsCs1naQ1tZfkuT3f/9QXuufPv4RKCM+Gya7U8easqU=",
|
| 197 |
+
"ops/kda/backends/__init__.py": "TtEq1fz8FfYrdqbSdZHPA9KNZXCgERZ8sINxDCYZxN8=",
|
| 198 |
+
"ops/kda/backends/flash_kda.py": "ncJlqPB9icS0hxx1gLWACHX1u9gWK9Zuz2OnLW7qSp8=",
|
| 199 |
+
"ops/kda/chunk.py": "Tc5Wt6dCdvv3AyIjn4HyiSNQ+PEhlz4vXd9oQOyDCro=",
|
| 200 |
+
"ops/kda/chunk_bwd.py": "/LwpwY5YXbqM7QLO2t0PogkAptPrR0y/tvRqVd0E20o=",
|
| 201 |
+
"ops/kda/chunk_fwd.py": "yPLK8XehVLVWe2dl5sX9eFjjxN5G1YX1rSKRyu8zLhI=",
|
| 202 |
+
"ops/kda/chunk_intra.py": "0iplpMZqGD//G1sLbMdY/hoksjAJu3qv0aBoOfHrNio=",
|
| 203 |
+
"ops/kda/chunk_intra_token_parallel.py": "a3dvImIfizoopyQ2i+fKtetL7001HavfOQENgqw16/I=",
|
| 204 |
+
"ops/kda/fused_recurrent.py": "KWsqM6LZXU2n7faYHMYMqwR/N1byanrjWc0R3Eogt6M=",
|
| 205 |
+
"ops/kda/gate.py": "sHa64RkSgT8vMYUiG0fYxmYQJMvt4mG2TKYCm+pa+nI=",
|
|
|
|
|
|
|
| 206 |
"ops/kda/naive.py": "YKMihdS2cGj/YztIu+irMQKAZtJPANJ+EhmaiPxz8BY=",
|
| 207 |
+
"ops/kda/wy_fast.py": "PasjSQorAguMGZkPwmVtosiTUlZ8x9jLiCln/UtX7bw=",
|
| 208 |
+
"ops/lightnet/__init__.py": "xI7MhtSqpNXoMRr9nmXTmq8swM+XjxBEsMH+9VKqwqA=",
|
| 209 |
+
"ops/lightnet/chunk.py": "7He3VzwLRiJ7avtCMje5Oz+nuRkMmtMEzdFUxLyEh04=",
|
| 210 |
+
"ops/lightnet/fused_recurrent.py": "hzn/dfLsBVrfpO44OQhreQIzysWT0LYHBoIubvphmVc=",
|
| 211 |
"ops/lightning_attn/__init__.py": "FPVVYNLjfO3GJQYIp+4HCQ4MdJtF8UZx5yktWDIatFA=",
|
| 212 |
+
"ops/lightning_attn/chunk.py": "w43Qdzp+ogeMkGAOL8ZvxVIFV/nBtlcN+5vn/oBhZCA=",
|
| 213 |
+
"ops/lightning_attn/fused_recurrent.py": "w98eqzLvLE4Gs8TR4iZvMl7X8mGjmL2+jSqTu0h3B6A=",
|
| 214 |
"ops/linear_attn/__init__.py": "3OeyduLmyi1manyo7FQz1ZLSoLgEXAKbHKn1uqDcK90=",
|
| 215 |
"ops/linear_attn/chunk.py": "5xqgOnPPA7nGPt/Rda4wOxSljFTD3Izw63VpuDLJNd8=",
|
| 216 |
"ops/linear_attn/fused_chunk.py": "MD6FycgZSdn8jV88UDvxpioPAw6hCxvsSq49qNIKpmo=",
|
| 217 |
"ops/linear_attn/fused_recurrent.py": "jUZ5gPuN2VngqbebHbN0lrIAOiZOYkxIku+C3Eh/9Vw=",
|
| 218 |
"ops/linear_attn/naive.py": "46BX2exbemO1c8XXVhmkz2m6H1ywTmrvT4/odStEA8g=",
|
| 219 |
+
"ops/linear_attn/utils.py": "tjqU7ST991YBV68Zs83Fy/li6sUSMeKNPGE3VcYMvfo=",
|
| 220 |
"ops/log_linear_attn/__init__.py": "qsAhfXSfoQBDmP6Li6+CjNd9ysMDGjcbYLonvcZcrjU=",
|
| 221 |
+
"ops/log_linear_attn/chunk.py": "21c+pLRtfBGC6RPf30KHsqafmCMBOcvL1SbjvNVUT9w=",
|
| 222 |
+
"ops/log_linear_attn/naive.py": "Ju7vJ7L6j1xSt2OrDHb1U8lXQ/G5c8TplDVwv2OGH6U=",
|
| 223 |
"ops/mesa_net/__init__.py": "32w1RDjxggXJ9JobAR01dDnN2UZSG2Fui7qePyQT2J4=",
|
| 224 |
+
"ops/mesa_net/chunk.py": "53VxbqZux86q96Jk7ZT7iHkLBlcADKp9yZuvBDovRhA=",
|
| 225 |
+
"ops/mesa_net/chunk_cg_solver_bwd.py": "6dUL+GS455oU+M2QOvROmJTlkGIyiNV2qD2Z/KmlY8I=",
|
| 226 |
+
"ops/mesa_net/chunk_cg_solver_fwd.py": "2xUtPW36YmUfqpj1qQblJpyYlzLO/LXnPWbH4cHyLoE=",
|
| 227 |
+
"ops/mesa_net/chunk_h_fwd.py": "kUhk8XVi9GPrfuViwL4shPieN3ZCZs9hvqaT7L7Bf7g=",
|
| 228 |
+
"ops/mesa_net/chunk_h_kk_intra_bwd.py": "TzV3RiE5k3/C38J30lgLcoHHj1fWiT+39iHlZPrNLvM=",
|
| 229 |
+
"ops/mesa_net/chunk_h_kv_intra_bwd.py": "b4s2qkF5ANeggNE8HrNZT8LEfd02FqTLo1+KY4wJKos=",
|
| 230 |
+
"ops/mesa_net/chunk_h_kv_intra_bwd_separate.py": "6g3MpZX8313sLrlMhGuwA7MY2e+wVX56xgwqoWj3OZA=",
|
| 231 |
+
"ops/mesa_net/decoding_one_step.py": "D3QQNRDvQkfFnQ5CV77pK32GqM4nI8h5QqBgH95uBdI=",
|
| 232 |
"ops/mesa_net/naive.py": "zv3jT+71UegNb0JyIKnPv8OddyzHu4weEETtt0nJvzA=",
|
| 233 |
"ops/moba/__init__.py": "P7ARNbLLMsmTtxcxPk09NPmjcvHGwWCmooXPYvT6ANk=",
|
| 234 |
+
"ops/moba/parallel.py": "vlJbZdAJkBvuqbgjTD03lQvB5BK4kagpC1PCMYQdO0c=",
|
| 235 |
+
"ops/momentum_delta_rule/__init__.py": "5OaHW/StrtV3AXsAel5gY1tFYo/vIktNiATrRNV6C3Q=",
|
| 236 |
+
"ops/momentum_delta_rule/chunk.py": "PMijn0zk+fco7T3jTPV3AiGJjeL3c9wyxYGozOFRU4E=",
|
| 237 |
+
"ops/momentum_delta_rule/fused_recurrent.py": "gUZQM29isdhTDKa4eKL/lvzr2fZwe/iu2saM6hvanJo=",
|
| 238 |
+
"ops/momentum_delta_rule/naive.py": "p6i6fC2NbwyGyAa7BroNb//NKET5cWPuciubVEYq2Ws=",
|
| 239 |
"ops/nsa/__init__.py": "6Mw2zDl4Z74QXVjME1d88PMSKTSO/AYUa00lW/IK+eI=",
|
| 240 |
+
"ops/nsa/compression.py": "XxTFQ7YicVLJ/RajeCgkQKUPKDq+t03lMtjgirTk7Mc=",
|
| 241 |
+
"ops/nsa/naive.py": "zJ1lQnQEvnF6G6j/n1HF31DDYPQOENL/fJfBlWM4a+k=",
|
| 242 |
+
"ops/nsa/parallel.py": "SQEcy8p6KEX+MbIRY+/o9IblXJPRTcMOMdJk9i4kSdo=",
|
| 243 |
"ops/nsa/utils.py": "lbhybLC0CqXTn6liY8d1sQfTdZ2Gl+++Y5Go53OX4xE=",
|
| 244 |
"ops/parallax/__init__.py": "g2pTOybF7cyoyaMAku1gpjV5MBY6s/Ll1X2NT6/w/YM=",
|
| 245 |
+
"ops/parallax/decode.py": "RMgM4i3NxaiktyPLxuF2wgPytE6Os7vbywv9DovgQVM=",
|
| 246 |
+
"ops/parallax/naive.py": "Bul9UJn1oJgW3Q2R04b/aQ87GIBx8Pu+DMalkXdmf8g=",
|
| 247 |
+
"ops/parallax/parallel.py": "U1/dvoFO4sXS3c13BHbMzbdUdM8rACR0aoGuS7cXxGw=",
|
| 248 |
"ops/path_attn/__init__.py": "eyvdV5LkkxztzDTDYAl862vhXITUOcMtF6D8n6n0O/E=",
|
| 249 |
+
"ops/path_attn/cumprod_householder_bwd.py": "aheXzKc/5z9ug392HO9RvnRLfuoB2IqMDqJGCoQHdW0=",
|
| 250 |
+
"ops/path_attn/cumprod_householder_fwd.py": "Z+994gihtCIHIVOQDpsZG40KAY2h3QoPhRWSZ5xTM88=",
|
| 251 |
+
"ops/path_attn/intra_chunk_preprocess_bwd.py": "vznrWNVjKSVqJnroNX0rdTzZubF6gzBfIo30UKH/EAs=",
|
| 252 |
+
"ops/path_attn/intra_chunk_preprocess_bwd_prepare.py": "m8JxIsdrK/0RQgoA4pCpdvjTEz61TI1yZ2ga7H6NZfE=",
|
| 253 |
+
"ops/path_attn/intra_chunk_preprocess_fwd.py": "Dl+JNpXxX2WYfFWC6pGWSDnN1yJPJdHVLoJ41t/tgN4=",
|
| 254 |
"ops/path_attn/naive.py": "4QsKiZUcF0q4IJbrku4Xu/IR3YBg+n6Epio7FAOW9lk=",
|
| 255 |
"ops/path_attn/parallel.py": "V1c/T2VKbs8MgNJ0AT2JA5ULpx49aLb5maoxizAbVjk=",
|
| 256 |
+
"ops/path_attn/parallel_path_bwd_inter_dkv.py": "mtVBfPgeTWxQWjcQfee4Kk/KRmck4kEwADFuT+PfcOg=",
|
| 257 |
+
"ops/path_attn/parallel_path_bwd_inter_dqh.py": "moIY1PhioPDmbWQc7T37Tx25kKn/1OrDGPsBOai1xTg=",
|
| 258 |
+
"ops/path_attn/parallel_path_bwd_intra.py": "w1sn58vCEin95acLyFmq+XQDQbGiiIU6vM8J/Xp5faw=",
|
| 259 |
+
"ops/path_attn/parallel_path_fwd.py": "uRUFU10eJB9ZCDcVn4AYM5+JdTRdKPKh7z5cpEEE+Ng=",
|
| 260 |
+
"ops/path_attn/prepare_k_cache.py": "DOuhtk1NY0PG0WSTxQcc8EvY3zFvTFRRLkyd9pztOaI=",
|
| 261 |
+
"ops/path_attn/transform_q.py": "qpu6Y3/BBj9K4dYP7Nj9QB/9zVOc0FHZY0NumyoyZLo=",
|
| 262 |
+
"ops/precond_gated_delta_rule/__init__.py": "E05uI9A1ocZvCySI4+nu41mCPr4MJmZA1upU7ruAHM8=",
|
| 263 |
+
"ops/precond_gated_delta_rule/backends/__init__.py": "hoBAVLZQ+jOiVYJWE5G4A1doL5gqeqP/Dz0istkBoeg=",
|
| 264 |
+
"ops/precond_gated_delta_rule/chunk.py": "d6aY4870cAoSyBkY063zvl57SHM9G31OZ6OUYL80OaE=",
|
| 265 |
+
"ops/precond_gated_delta_rule/chunk_precond_kkt_fwd.py": "4rEy83SMB79qql+FGOl5aQ66OYTj6D5vtNEgjcJEBrA=",
|
| 266 |
+
"ops/precond_gated_delta_rule/chunk_precond_wy_bwd.py": "eNSvTIyY+LfG5O3PLIasH3+vEsVg9uFYeo5f2Wjlwmw=",
|
| 267 |
+
"ops/precond_gated_delta_rule/fused_recurrent.py": "xRZ3yREutRIZ2qFVeS5u4QCy3byrePYRhL859UenVG0=",
|
| 268 |
+
"ops/precond_gated_delta_rule/naive.py": "O6pnpfNdxyMGmOPxdh7IZ1ExMYwV1KJ+1/L84R6Eteg=",
|
| 269 |
+
"ops/precond_kda/__init__.py": "KA5gjXPBlmGs6vc1Srg4zngR+5FXv+O2a0VJJDHrY0M=",
|
| 270 |
+
"ops/precond_kda/chunk.py": "KUpUtIX0ogoKnxatK5SMPdJ7Ms3lX5zvbSd4Y70Jm10=",
|
| 271 |
+
"ops/precond_kda/chunk_bwd.py": "pwNynFCythreiWjz6ezuDjZ2eqNdTmYj1PqysBdWCSc=",
|
| 272 |
+
"ops/precond_kda/chunk_intra.py": "gcm/6QihmSSHoN4DhSqNGuY2RPrbKp60ENBODhsi30o=",
|
| 273 |
+
"ops/precond_kda/chunk_intra_token_parallel.py": "ayBWo/wqF/AiU9qLC7jHmZbk04iGBcd9/FNeY7CuHDQ=",
|
| 274 |
+
"ops/precond_kda/fused_recurrent.py": "+RTPNLwCt8JVTL54hHmRqvEHLLJeLYn+a/9VKrzD3vY=",
|
| 275 |
+
"ops/precond_kda/naive.py": "7Bj6uTWYmCxBRHuOCzs+PhkWtxlFsTGkVXAzZGzhh8U=",
|
| 276 |
+
"ops/precond_kda/wy_fast.py": "pj8DLVEG5/XHWFj9SICxTKphtgmrz4Zvu+giMq8NFaY=",
|
| 277 |
"ops/rebased/__init__.py": "pawYkzOJ/mQY5Qj0Ibuq81P3KNgO9Lv6swOxCjlDlGs=",
|
| 278 |
"ops/rebased/naive.py": "XOrMn2Ohd7MDJ7QvP93dPfjv/6prnZW/ozxHtU0KqWQ=",
|
| 279 |
+
"ops/rebased/parallel.py": "cBnn/KTq9FlWJIpc6Jj9uJ7J14VfGFadrxABo4bsoQc=",
|
| 280 |
"ops/retention/__init__.py": "i6uHA1ndTR6T/fVfooceKo12wyBFGYLe1EAm0Mo/sg0=",
|
| 281 |
+
"ops/retention/chunk.py": "LyunHUb/Y0ItUN9EDTaix4N3Zd2e/7D9AoOQTSXyAMM=",
|
| 282 |
+
"ops/retention/fused_chunk.py": "Nzn6nYHcMyjL8uOWkwD10Htbn28xhomLMG4XZ0p7ru0=",
|
| 283 |
+
"ops/retention/fused_recurrent.py": "WGV6AAdpoGG79XgHWkjDkFWY9ZpvE99xmqwre64KuZA=",
|
| 284 |
"ops/retention/naive.py": "MG107SmOiRKLTZ8ziqaWN85nbgIPj/GqNJJ7KMt5Tag=",
|
| 285 |
+
"ops/retention/parallel.py": "WRBtqBxCWpIZ/Lm2u3bXwnbeLbwwQ9ZrrajeYeNBoTg=",
|
| 286 |
"ops/rwkv4/__init__.py": "GnWakdtZiQJ0+fTYxqqIyosoPwjH6Yp8P1AbpHIDnts=",
|
| 287 |
+
"ops/rwkv4/fused_recurrent.py": "LG9PdTsubmJvgqvbDvT8N+9y5SWQZZXfTxC0Hg1jU5s=",
|
| 288 |
"ops/rwkv6/__init__.py": "wPYgC6wG+xc4I2vessGhv1EaZ4tL5yuVQVSwi1rEEUk=",
|
| 289 |
+
"ops/rwkv6/backends/__init__.py": "3Hgm1GsMIil45jzcS+4PB9iZi77lM/W+P4hBlV1+fj8=",
|
| 290 |
+
"ops/rwkv6/chunk.py": "scQIA9mDVrEFjX5IoVNG7WRDmr9ss+cZBTqLDVkiEKk=",
|
| 291 |
"ops/rwkv6/chunk_naive.py": "zyj0Og15jGxNMzmlD9FoEdf/odzu3tqio/jiceVMNk4=",
|
| 292 |
+
"ops/rwkv6/fused_recurrent.py": "Nriss1l8NCBYj3y/tIJJLEScxNo5BUXQcqOYe2T4Hac=",
|
| 293 |
"ops/rwkv6/recurrent_naive.py": "/lCgua1vSaJDqA4tOWWUaVxol5Axi3cOcjI+mJj7OAM=",
|
| 294 |
"ops/rwkv7/__init__.py": "dPKBISLNnwlKb+xp/8ejsc2peC9gKQ3NedtMT5wQ1sE=",
|
| 295 |
+
"ops/rwkv7/channel_mixing.py": "xJAzrxM8dRByDCC9DdLRi2Q56AzxDKWPcpg5nhyo4wU=",
|
| 296 |
+
"ops/rwkv7/chunk.py": "jiQCm20KhWEfM3MT99MCmm3LJZyWQSetiASzBEg5P4U=",
|
| 297 |
+
"ops/rwkv7/fused_addcmul.py": "ZQ437Ks75Hw3qa7F+iV+dx76TKl7nGcyJd0IEvkAEIk=",
|
| 298 |
+
"ops/rwkv7/fused_k_update.py": "NuR4O/dI+4UHVqwKLxgBBsXC7SCaCpTAed6cY2cy4qE=",
|
| 299 |
+
"ops/rwkv7/fused_recurrent.py": "EUJaU6go5WjhYB9WrAhOriB04cr5nuvCJwGuxNDp/1U=",
|
| 300 |
+
"ops/rwkv7/gate_output_correction.py": "rwkLmmd3vqW8dvoJIR7f7uz4iR8PgEWBMnQbLb582k4=",
|
| 301 |
+
"ops/simple_gla/__init__.py": "qHTqgCNXrTUUrTSo+ZG6B553XTCDonl3K58OpQ7YcMg=",
|
| 302 |
+
"ops/simple_gla/backends/__init__.py": "ZxTK7vZktZ7TBQB/5oiJr+oIypQU1cgkbn/ybwJl450=",
|
| 303 |
+
"ops/simple_gla/chunk.py": "wmKvR5zeIRZZal2YiPRSXZVp6bJoc5brUfAV1fjbKjw=",
|
| 304 |
+
"ops/simple_gla/fused_chunk.py": "gN1IUd+GV72DsTw+q9Ye2cMDCrfm9ZYv7dN1/+NHuPs=",
|
| 305 |
+
"ops/simple_gla/fused_recurrent.py": "UukysuAEhW46kvKCjDNfyfAjNFT2LF4QqZZMvtg+GMc=",
|
| 306 |
"ops/simple_gla/naive.py": "g3fAN++vd0aWvZcdOW7Y0boMYcs2mOld8kePWRbl2R0=",
|
| 307 |
+
"ops/simple_gla/parallel.py": "6jkeEIyN0tHrMGG/PMcPpSHfJK1Gg6OpGpguPhjqulk=",
|
| 308 |
+
"ops/stickbreaking_attn/__init__.py": "A3p1HEdTYG4f0TLRWGSWQTySjsfOVHbX+Eg7KFyXpQM=",
|
| 309 |
+
"ops/stickbreaking_attn/naive.py": "P4jkKUVtTg7ImxWWfxbZzFsq//W5jfgeLM7gYVQTClk=",
|
| 310 |
+
"ops/stickbreaking_attn/parallel.py": "jqY7jl1yRSzCfTO1QtYmXPqKQfS+UdiyVQ1XCFCOKWg=",
|
| 311 |
"ops/titans/__init__.py": "4t9OK1aYdW03I+sUlfUjj3ALTez1M/XFD/H6KzeZtGc=",
|
| 312 |
"ops/titans/log_impl.py": "Y5tMWJgtVE+GX394DdxQHd6Yirrg3sLx6sinMdQvkAE=",
|
| 313 |
+
"ops/titans/naive.py": "0Y4R5926mX2CgYI55MjxVfn6p2X4iM4pABCzmVZ9d5c=",
|
| 314 |
"ops/ttt/__init__.py": "cFaLRxAWRsKjcmXh01bJbh5U59ZaFaM7DwYgm/KBAbo=",
|
| 315 |
+
"ops/ttt/chunk.py": "Pyon33URTqVwxnprbp9AC7yZcY99MXBWTOxnf1iAxow=",
|
| 316 |
+
"ops/ttt/fused_chunk.py": "uVBNMzpMgEozAEuzis/xYVpBrDrxf3mcnWyfw3Lr9Yo=",
|
| 317 |
+
"ops/ttt/naive.py": "oSWlwYF9ngQShNodpdkaIwb3ndI4RH0jB2jssaKv89s=",
|
| 318 |
+
"ops/utils/__init__.py": "3NBO3K+KTaQeR4ebY6LYdLOhdUxGFOPSqdAQPLhJt/I=",
|
| 319 |
+
"ops/utils/cache.py": "qP/aHKYJ7682YgeoetUAIlPTn9S14f2URjRSRdEQ5vk=",
|
|
|
|
|
|
|
|
|
|
| 320 |
"ops/utils/constant.py": "uVK9zwOd7kM/DPSQk8cllx5nkYeK0K/KZVyCu0ZFdPg=",
|
| 321 |
+
"ops/utils/csr.py": "3s/+zgzuhMNIRo9UyriDR+Z94AOfAnx0VAD2VdmCszQ=",
|
| 322 |
+
"ops/utils/cumsum.py": "0Y9Lu/0qZLxT05txmpYuwvbmuxlgAsF6mnejbOp84xY=",
|
| 323 |
+
"ops/utils/graph.py": "uj5R0DV8gy3tW/VH9pT4xPn3Zb0CxYJWpH4zaU8KS6E=",
|
| 324 |
+
"ops/utils/index.py": "KeykCsBnOSNMGGgphH5OKFD/uqiva2rPGKUuqyj/8xk=",
|
| 325 |
+
"ops/utils/logcumsumexp.py": "ZpYz3i9FZI712XtDqIxCus8A4WamVFlYI8b6tHVbkXQ=",
|
| 326 |
+
"ops/utils/logsumexp.py": "qklce3jy76dN9WrNT1Bzw5F6Ime+mo00deKYryTMLTk=",
|
| 327 |
+
"ops/utils/matmul.py": "1X2PdPmFwXEf3ruaLZHBLFrYBwgmh5k+GOP5fuKM5Jw=",
|
| 328 |
+
"ops/utils/op.py": "Y/Kcks768kujwclindhHtbnQxyJje7mMBVReDvegK1Q=",
|
| 329 |
+
"ops/utils/pack.py": "92z4AmmkdpJ5rryTNHjB+BkSmlsBU5ssXJqPoLXqdFc=",
|
| 330 |
+
"ops/utils/pooling.py": "mtioM2xOtxMCEJDBfR+lVxhdg1x3NdBV8PVK+zOb/6Q=",
|
| 331 |
+
"ops/utils/sinkhorn/__init__.py": "7AY27ZaP2G/gGqo/equFKp9hLHUcAp6Mmi8xE3UGBGc=",
|
| 332 |
+
"ops/utils/sinkhorn/gluon.py": "bJ9FjAXod5fuweW1T6pP3C1Q6esQRDiS/MchqGZKtIU=",
|
| 333 |
+
"ops/utils/sinkhorn/naive.py": "WZYZzlJ/atDmXzRnJFFMWfB/t5JIytpzxLz98palzq8=",
|
| 334 |
+
"ops/utils/sinkhorn/ops.py": "2UH9sL5DsBPRcr+vUgahTvOaI9Myg2cnnZv7oclXx/s=",
|
| 335 |
+
"ops/utils/softmax.py": "aCTHGnayRqCA6PAd9edtVeb9EoFNfzJdBmDtRZiMZN0=",
|
| 336 |
+
"ops/utils/softplus.py": "Ykhyi0d+jM2zEyFp8fQqmFNqQmsU5XzUbUpn+jr/Rn0=",
|
| 337 |
+
"ops/utils/solve_tril.py": "4j2C13HQCr+F5URwwLUO4t3Dag6upnlpGwNew17nphs=",
|
| 338 |
"ops/wall_attn/__init__.py": "r/FbDGjGO8WK1DaMbl9axWHpENUa3pzSc0v9qviHJ6I=",
|
| 339 |
+
"ops/wall_attn/decode.py": "o5q0fsJTiz+0XW0RPFFI1hBXz6PXSBMSTvog8Bc+sGA=",
|
| 340 |
"ops/wall_attn/naive.py": "9YKwBSvQ9imy229T5KMYKpuVNb+xEzhXsXdMemRWqjQ=",
|
| 341 |
+
"ops/wall_attn/parallel.py": "k1DMCeZ/dLyUrpaLt1eWphG3WA0STXIwofUU2/lZx1g=",
|
| 342 |
+
"symbols.json": "XeDbgUU3taJ6OhnIi2xuHQpY5Guf0MQ5YL5XFWYzxl0=",
|
| 343 |
+
"utils/__init__.py": "+7iYDYAJEDL9y/TTl/bNr5/O0LpSylNyE6J7c1OCAxs=",
|
| 344 |
+
"utils/decorators.py": "Xy1DCGkQ7HRyffUHEXsVLhn6LE7xgdIY9Yob1GFm/f8=",
|
| 345 |
+
"utils/env.py": "LJZbQTALlKpcS2dwt7JBv/AdlZ8Yh7LC7tCDDJs0D2M=",
|
| 346 |
+
"utils/hardware.py": "2AA4GxTL1WNYIzRJQF3OXCCuATnobx928o6bjXD0U04=",
|
| 347 |
+
"utils/layers.py": "afB10gGysmmVfVRlPnduPpuvcdAeDAstmqPC0sYJbRw=",
|
| 348 |
+
"utils/testing.py": "KXWwCDYOxKLEYFxzZgFfh/3kxzMm+12Vq4IsxJaoPlM="
|
|
|
|
|
|
|
| 349 |
}
|
| 350 |
},
|
| 351 |
"provenance": {
|
|
|
|
| 355 |
"dirty": false
|
| 356 |
},
|
| 357 |
"kernel": {
|
| 358 |
+
"commit": "faa8674647aa5ebaab5e997cd11e6e3808d090a9",
|
| 359 |
"dirty": false
|
| 360 |
}
|
| 361 |
}
|
build/torch-cuda/metadata.json.sigstore
CHANGED
|
@@ -1 +1 @@
|
|
| 1 |
-
{"mediaType":"application/vnd.dev.sigstore.bundle.v0.3+json","verificationMaterial":{"certificate":{"rawBytes":"MIIHLTCCBrOgAwIBAgIUQ629eN4hUTIWupwbogDv3RA6AyEwCgYIKoZIzj0EAwMwNzEVMBMGA1UEChMMc2lnc3RvcmUuZGV2MR4wHAYDVQQDExVzaWdzdG9yZS1pbnRlcm1lZGlhdGUwHhcNMjYxMDE5MTMxODIzWhcNMjYxMDE5MTMyODIzWjAAMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEpl17UO4EUwHQu4gYHIYYLubpp8Zzl5lYFeFTp4LxxeYjaO9yg8RCS6mWZc2nLEcA3HNjkFi4C6oGo/oG5gs1KaOCBdIwggXOMA4GA1UdDwEB/wQEAwIHgDATBgNVHSUEDDAKBggrBgEFBQcDAzAfBgNVHSMEGDAWgBTf0+nPViQRlvmo2OkoVaLGLhhkPzBrBgNVHREBAf8EYTBfhl1odHRwczovL2dpdGh1Yi5jb20vaHVnZ2luZ2ZhY2Uva2VybmVscy1jb21tdW5pdHkvLmdpdGh1Yi93b3JrZmxvd3MvYnVpbGQueWFtbEByZWZzL2hlYWRzL21haW4wOQYKKwYBBAGDvzABAQQraHR0cHM6Ly90b2tlbi5hY3Rpb25zLmdpdGh1YnVzZXJjb250ZW50LmNvbTAfBgorBgEEAYO/MAECBBF3b3JrZmxvd19kaXNwYXRjaDA2BgorBgEEAYO/MAEDBChmZTJiYjY2ZmVlNmMyYTc3ZWNjZjA4YTA1MDhkYzU3NDI4ZDQ4OGVkMBMGCisGAQQBg78wAQQEBUJ1aWxkMCsGCisGAQQBg78wAQUEHWh1Z2dpbmdmYWNlL2tlcm5lbHMtY29tbXVuaXR5MB0GCisGAQQBg78wAQYED3JlZnMvaGVhZHMvbWFpbjA7BgorBgEEAYO/MAEIBC0MK2h0dHBzOi8vdG9rZW4uYWN0aW9ucy5naXRodWJ1c2VyY29udGVudC5jb20wbQYKKwYBBAGDvzABCQRfDF1odHRwczovL2dpdGh1Yi5jb20vaHVnZ2luZ2ZhY2Uva2VybmVscy1jb21tdW5pdHkvLmdpdGh1Yi93b3JrZmxvd3MvYnVpbGQueWFtbEByZWZzL2hlYWRzL21haW4wOAYKKwYBBAGDvzABCgQqDChmZTJiYjY2ZmVlNmMyYTc3ZWNjZjA4YTA1MDhkYzU3NDI4ZDQ4OGVkMBsGCisGAQQBg78wAQsEDQwLc2VsZi1ob3N0ZWQwQAYKKwYBBAGDvzABDAQyDDBodHRwczovL2dpdGh1Yi5jb20vaHVnZ2luZ2ZhY2Uva2VybmVscy1jb21tdW5pdHkwOAYKKwYBBAGDvzABDQQqDChmZTJiYjY2ZmVlNmMyYTc3ZWNjZjA4YTA1MDhkYzU3NDI4ZDQ4OGVkMB8GCisGAQQBg78wAQ4EEQwPcmVmcy9oZWFkcy9tYWluMBoGCisGAQQBg78wAQ8EDAwKMTA3MTQ3NTUyOTAuBgorBgEEAYO/MAEQBCAMHmh0dHBzOi8vZ2l0aHViLmNvbS9odWdnaW5nZmFjZTAYBgorBgEEAYO/MAERBAoMCDI1NzIwNzQzMG0GCisGAQQBg78wARIEXwxdaHR0cHM6Ly9naXRodWIuY29tL2h1Z2dpbmdmYWNlL2tlcm5lbHMtY29tbXVuaXR5Ly5naXRodWIvd29ya2Zsb3dzL2J1aWxkLnlhbWxAcmVmcy9oZWFkcy9tYWluMDgGCisGAQQBg78wARMEKgwoZmUyYmI2NmZlZTZjMmE3N2VjY2YwOGEwNTA4ZGM1NzQyOGQ0ODhlZDAhBgorBgEEAYO/MAEUBBMMEXdvcmtmbG93X2Rpc3BhdGNoMGQGCisGAQQBg78wARUEVgxUaHR0cHM6Ly9naXRodWIuY29tL2h1Z2dpbmdmYWNlL2tlcm5lbHMtY29tbXVuaXR5L2FjdGlvbnMvcnVucy8zOTIzOTU0OTYzNS9hdHRlbXB0cy8xMBYGCisGAQQBg78wARYECAwGcHVibGljMEYGCisGAQQBg78wARgEOAw2cmVwbzpodWdnaW5nZmFjZS9rZXJuZWxzLWNvbW11bml0eTpyZWY6cmVmcy9oZWFkcy9tYWluMIGLBgorBgEEAdZ5AgQCBH0EewB5AHcA3T0wasbHETJjGR4cmWc3AqJKXrjePK3/h4pygC8p7o4AAAGhVFAuVgAABAMASDBGAiEAtnEys30x7Ya9hsVCz7RWdn6nYXSqgMVDe8yHwixSiiYCIQCdcOvWSnZSR+oCBuEqRzBjvDTsmBBOA7bQNQdRM+tFVjAKBggqhkjOPQQDAwNoADBlAjB44h8gf51LU8aLNgDS8WUfSC7PpbdOXA/MDkX3XPLQa7tTAnTW9IgnghlRkSCVIdUCMQDgufgY6hRhjInveoC0gxGEucYH3gdJZ7qJkooniD5e5OD64vpL9D2zpvlaZC+N+Y8="},"tlogEntries":[{"logIndex":"3321382366","logId":{"keyId":"wNI9atQGlz+VWfO6LRygH4QUfY/8W4RFwiT5i5WRgB0="},"kindVersion":{"kind":"hashedrekord","version":"0.0.1"},"integratedTime":"1792415903","inclusionPromise":{"signedEntryTimestamp":"MEQCIA8Pb2l/03SWHSHoQlVPnuD3qoB1EObRvw8TSvdRmXHCAiBLQW9zMHeh1g3bHLP1y44z5xADQsM8tsSXvzGp0GMBYA=="},"inclusionProof":{"logIndex":"3199478104","rootHash":"4tHHO4qqAF/BE6oVRgF0boQq/yTfvz0KIX8pAsRo3G0=","treeSize":"3199478328","hashes":["boitsHdOY++pKowb8ip8eWyv+giOG6c3LLDf4d59mB0=","qcf970yQgX2TVWwq1E7iCbQrykhEhaftOyMyVe+h/N4=","EslsDaCqZixXslWYzeNOIgKnH6afg5sQlM2aEpV4jq0=","FtY90QTdG+QWhCzKV56/dsHTXqKp04sOsj4tjwrBhI8=","1Du/xr+ro1zVy3zI5m0v/GyxJcdIShmHLA8zKq/JJrc=","6akUiAwNlsFQQrqdMshpY6Nr7bcHUIKiutTPw9YSiOY=","eJJgNMmRIOUXkgOpxCA8t3Iu0nU2BvsYyb5Fuo48Z/s=","gqCLyzcTY8N5+rych9c4HRspuMPAmRkae5U4ACwbpaM=","r4uw63XA1OsTh4/HhkQY/Veqn7iADlv2k7521RDZtlw=","mIeT670PcvMS00qGZ9uqtj9ZBspJzyCniPsKBf9FQ1M=","OXA2SiOGgZ4Atk3yCE3v98reKXHty7rZAo82yZi0yls=","eE+LYckVfbRCjJTwQL99tuBkmhXXjKkrIh1lVDPm+hs=","WF6g44nOcJ5AK5U4U6CvcX9NPmGRLXdvfv+hcf011hw=","kHa2Ke03zePMosAfwPNg2y4kk1ZwjdZi4MKNVX7epiE=","uCZQe757l2sS1c05Y7TzOwEm+X8MeGLIUCkEOmFVOz4=","nyQV/+cWQUG5Hb2PKjQQNkQIJmz2qzAZKBQlkHGIknM=","G+nk7mgE5h6dUmv2UY7NDJrY3WvrZY31raaO1AETt+o=","qlTWNDzERnTBQVcHHXXVPjiUP0SsikGxfcxVlgqVFDo=","gg9GNApNke3+zNhl4tsWtmIycCFrOMCB3lys6XuSQNQ=","NlOclldmKPA1tMKIskqHAwuQDYHp31YwpK+OOMrMccc=","qxzHanAzz57SDdmJe0B7bJK72NTIBbwEMGBBKvDOROw=","xH/DCseLHr9eKoYT8qsORZK7zVdEGYWHuVtsVrD95wY="],"checkpoint":{"envelope":"rekor.sigstore.dev - 1193050959916656506\n3199478328\n4tHHO4qqAF/BE6oVRgF0boQq/yTfvz0KIX8pAsRo3G0=\n\n— rekor.sigstore.dev wNI9ajBEAiANt/PrcbDQqVmXByPf3zWgItoN7m+bQariPJGNVfk0hwIgNtxR5MYteCwgnROrvIy4TnFG1I1+jhaTEfNh7ViG12U=\n"}},"canonicalizedBody":"eyJhcGlWZXJzaW9uIjoiMC4wLjEiLCJraW5kIjoiaGFzaGVkcmVrb3JkIiwic3BlYyI6eyJkYXRhIjp7Imhhc2giOnsiYWxnb3JpdGhtIjoic2hhMjU2IiwidmFsdWUiOiIwZTE2NWUzMmY5ZDdlNzEyNWVkMjJhYWZlMTY1YzNiYjEyNjA4MThmN2E3YjUwZDdhNTkyOGE4MTI5OWQ1ZjRjIn19LCJzaWduYXR1cmUiOnsiY29udGVudCI6Ik1FVUNJR3VFSllNbGZJcGZCZXBqMFN1Nk5iLzMxSEdibVpuZzVVRnRUajJwWStPSUFpRUE4R1d4RDlNOXJVdU1od0pMVU53RERFR1ZWVHJ0MXViUHFsOUl1b2R5SDdvPSIsInB1YmxpY0tleSI6eyJjb250ZW50IjoiTFMwdExTMUNSVWRKVGlCRFJWSlVTVVpKUTBGVVJTMHRMUzB0Q2sxSlNVaE1WRU5EUW5KUFowRjNTVUpCWjBsVlVUWXlPV1ZPTkdoVlZFbFhkWEIzWW05blJIWXpVa0UyUVhsRmQwTm5XVWxMYjFwSmVtb3dSVUYzVFhjS1RucEZWazFDVFVkQk1WVkZRMmhOVFdNeWJHNWpNMUoyWTIxVmRWcEhWakpOVWpSM1NFRlpSRlpSVVVSRmVGWjZZVmRrZW1SSE9YbGFVekZ3WW01U2JBcGpiVEZzV2tkc2FHUkhWWGRJYUdOT1RXcFplRTFFUlRWTlZFMTRUMFJKZWxkb1kwNU5hbGw0VFVSRk5VMVVUWGxQUkVsNlYycEJRVTFHYTNkRmQxbElDa3R2V2tsNmFqQkRRVkZaU1V0dldrbDZhakJFUVZGalJGRm5RVVZ3YkRFM1ZVODBSVlYzU0ZGMU5HZFpTRWxaV1V4MVluQndPRnA2YkRWc1dVWmxSbFFLY0RSTWVIaGxXV3BoVHpsNVp6aFNRMU0yYlZkYVl6SnVURVZqUVROSVRtcHJSbWswUXpadlIyOHZiMGMxWjNNeFMyRlBRMEprU1hkbloxaFBUVUUwUndwQk1WVmtSSGRGUWk5M1VVVkJkMGxJWjBSQlZFSm5UbFpJVTFWRlJFUkJTMEpuWjNKQ1owVkdRbEZqUkVGNlFXWkNaMDVXU0ZOTlJVZEVRVmRuUWxSbUNqQXJibEJXYVZGU2JIWnRiekpQYTI5V1lVeEhUR2hvYTFCNlFuSkNaMDVXU0ZKRlFrRm1PRVZaVkVKbWFHd3hiMlJJVW5kamVtOTJUREprY0dSSGFERUtXV2sxYW1JeU1IWmhTRlp1V2pKc2RWb3lXbWhaTWxWMllUSldlV0p0Vm5OamVURnFZakl4ZEdSWE5YQmtTR3QyVEcxa2NHUkhhREZaYVRrellqTktjZ3BhYlhoMlpETk5kbGx1Vm5CaVIxRjFaVmRHZEdKRlFubGFWMXA2VERKb2JGbFhVbnBNTWpGb1lWYzBkMDlSV1V0TGQxbENRa0ZIUkhaNlFVSkJVVkZ5Q21GSVVqQmpTRTAyVEhrNU1HSXlkR3hpYVRWb1dUTlNjR0l5TlhwTWJXUndaRWRvTVZsdVZucGFXRXBxWWpJMU1GcFhOVEJNYlU1MllsUkJaa0puYjNJS1FtZEZSVUZaVHk5TlFVVkRRa0pHTTJJelNuSmFiWGgyWkRFNWEyRllUbmRaV0ZKcVlVUkJNa0puYjNKQ1owVkZRVmxQTDAxQlJVUkNRMmh0V2xSS2FRcFphbGt5V20xV2JFNXRUWGxaVkdNeldsZE9hbHBxUVRSWlZFRXhUVVJvYTFsNlZUTk9SRWswV2tSUk5FOUhWbXROUWsxSFEybHpSMEZSVVVKbk56aDNDa0ZSVVVWQ1ZVb3hZVmQ0YTAxRGMwZERhWE5IUVZGUlFtYzNPSGRCVVZWRlNGZG9NVm95WkhCaWJXUnRXVmRPYkV3eWRHeGpiVFZzWWtoTmRGa3lPWFFLWWxoV2RXRllValZOUWpCSFEybHpSMEZSVVVKbk56aDNRVkZaUlVRelNteGFiazEyWVVkV2FGcElUWFppVjBad1ltcEJOMEpuYjNKQ1owVkZRVmxQTHdwTlFVVkpRa013VFVzeWFEQmtTRUo2VDJrNGRtUkhPWEphVnpSMVdWZE9NR0ZYT1hWamVUVnVZVmhTYjJSWFNqRmpNbFo1V1RJNWRXUkhWblZrUXpWcUNtSXlNSGRpVVZsTFMzZFpRa0pCUjBSMmVrRkNRMUZTWmtSR01XOWtTRkozWTNwdmRrd3laSEJrUjJneFdXazFhbUl5TUhaaFNGWnVXakpzZFZveVdtZ0tXVEpWZG1FeVZubGliVlp6WTNreGFtSXlNWFJrVnpWd1pFaHJka3h0WkhCa1IyZ3hXV2s1TTJJelNuSmFiWGgyWkROTmRsbHVWbkJpUjFGMVpWZEdkQXBpUlVKNVdsZGFla3d5YUd4WlYxSjZUREl4YUdGWE5IZFBRVmxMUzNkWlFrSkJSMFIyZWtGQ1EyZFJjVVJEYUcxYVZFcHBXV3BaTWxwdFZteE9iVTE1Q2xsVVl6TmFWMDVxV21wQk5GbFVRVEZOUkdocldYcFZNMDVFU1RSYVJGRTBUMGRXYTAxQ2MwZERhWE5IUVZGUlFtYzNPSGRCVVhORlJGRjNUR015Vm5NS1dta3hiMkl6VGpCYVYxRjNVVUZaUzB0M1dVSkNRVWRFZG5wQlFrUkJVWGxFUkVKdlpFaFNkMk42YjNaTU1tUndaRWRvTVZscE5XcGlNakIyWVVoV2JncGFNbXgxV2pKYWFGa3lWWFpoTWxaNVltMVdjMk41TVdwaU1qRjBaRmMxY0dSSWEzZFBRVmxMUzNkWlFrSkJSMFIyZWtGQ1JGRlJjVVJEYUcxYVZFcHBDbGxxV1RKYWJWWnNUbTFOZVZsVVl6TmFWMDVxV21wQk5GbFVRVEZOUkdocldYcFZNMDVFU1RSYVJGRTBUMGRXYTAxQ09FZERhWE5IUVZGUlFtYzNPSGNLUVZFMFJVVlJkMUJqYlZadFkzazViMXBYUm10amVUbDBXVmRzZFUxQ2IwZERhWE5IUVZGUlFtYzNPSGRCVVRoRlJFRjNTMDFVUVROTlZGRXpUbFJWZVFwUFZFRjFRbWR2Y2tKblJVVkJXVTh2VFVGRlVVSkRRVTFJYldnd1pFaENlazlwT0haYU1td3dZVWhXYVV4dFRuWmlVemx2WkZka2JtRlhOVzVhYlVacUNscFVRVmxDWjI5eVFtZEZSVUZaVHk5TlFVVlNRa0Z2VFVORVNURk9la2wzVG5wUmVrMUhNRWREYVhOSFFWRlJRbWMzT0hkQlVrbEZXSGQ0WkdGSVVqQUtZMGhOTmt4NU9XNWhXRkp2WkZkSmRWa3lPWFJNTW1neFdqSmtjR0p0WkcxWlYwNXNUREowYkdOdE5XeGlTRTEwV1RJNWRHSllWblZoV0ZJMVRIazFiZ3BoV0ZKdlpGZEpkbVF5T1hsaE1scHpZak5rZWt3eVNqRmhWM2hyVEc1c2FHSlhlRUZqYlZadFkzazViMXBYUm10amVUbDBXVmRzZFUxRVowZERhWE5IQ2tGUlVVSm5OemgzUVZKTlJVdG5kMjlhYlZWNVdXMUpNazV0V214YVZGcHFUVzFGTTA0eVZtcFpNbGwzVDBkRmQwNVVRVFJhUjAweFRucFJlVTlIVVRBS1QwUm9iRnBFUVdoQ1oyOXlRbWRGUlVGWlR5OU5RVVZWUWtKTlRVVllaSFpqYlhSdFlrYzVNMWd5VW5Cak0wSm9aRWRPYjAxSFVVZERhWE5IUVZGUlFncG5OemgzUVZKVlJWWm5lRlZoU0ZJd1kwaE5Oa3g1T1c1aFdGSnZaRmRKZFZreU9YUk1NbWd4V2pKa2NHSnRaRzFaVjA1c1RESjBiR050Tld4aVNFMTBDbGt5T1hSaVdGWjFZVmhTTlV3eVJtcGtSMngyWW01TmRtTnVWblZqZVRoNlQxUkplazlVVlRCUFZGbDZUbE01YUdSSVVteGlXRUl3WTNrNGVFMUNXVWNLUTJselIwRlJVVUpuTnpoM1FWSlpSVU5CZDBkalNGWnBZa2RzYWsxRldVZERhWE5IUVZGUlFtYzNPSGRCVW1kRlQwRjNNbU50Vm5kaWVuQnZaRmRrYmdwaFZ6VnVXbTFHYWxwVE9YSmFXRXAxV2xkNGVreFhUblppVnpFeFltMXNNR1ZVY0hsYVYxazJZMjFXYldONU9XOWFWMFpyWTNrNWRGbFhiSFZOU1VkTUNrSm5iM0pDWjBWRlFXUmFOVUZuVVVOQ1NEQkZaWGRDTlVGSVkwRXpWREIzWVhOaVNFVlVTbXBIVWpSamJWZGpNMEZ4U2t0WWNtcGxVRXN6TDJnMGNIa0taME00Y0Rkdk5FRkJRVWRvVmtaQmRWWm5RVUZDUVUxQlUwUkNSMEZwUlVGMGJrVjVjek13ZURkWllUbG9jMVpEZWpkU1YyUnVObTVaV0ZOeFowMVdSQXBsT0hsSWQybDRVMmxwV1VOSlVVTmtZMDkyVjFOdVdsTlNLMjlEUW5WRmNWSjZRbXAyUkZSemJVSkNUMEUzWWxGT1VXUlNUU3QwUmxacVFVdENaMmR4Q21ocmFrOVFVVkZFUVhkT2IwRkVRbXhCYWtJME5HZzRaMlkxTVV4Vk9HRk1UbWRFVXpoWFZXWlRRemRRY0dKa1QxaEJMMDFFYTFneldGQk1VV0UzZEZRS1FXNVVWemxKWjI1bmFHeFNhMU5EVmtsa1ZVTk5VVVJuZFdabldUWm9VbWhxU1c1MlpXOURNR2Q0UjBWMVkxbElNMmRrU2xvM2NVcHJiMjl1YVVRMVpRbzFUMFEyTkhad1REbEVNbnB3ZG14aFdrTXJUaXRaT0QwS0xTMHRMUzFGVGtRZ1EwVlNWRWxHU1VOQlZFVXRMUzB0TFFvPSJ9fX19"}],"timestampVerificationData":{"rfc3161Timestamps":[{"signedTimestamp":"MIICyjADAgEAMIICwQYJKoZIhvcNAQcCoIICsjCCAq4CAQMxDTALBglghkgBZQMEAgEwgbcGCyqGSIb3DQEJEAEEoIGnBIGkMIGhAgEBBgkrBgEEAYO/MAIwMTANBglghkgBZQMEAgEFAAQgM+jtpRT7VTayyXNU6XeuWevLOHSgymjIR3AhSqAF5ZoCFDPzZCiwDE+g/BiHrxxd5OfIKibdGA8yMDI2MTAxOTEzMTgyM1owAwIBAaAypDAwLjEVMBMGA1UEChMMc2lnc3RvcmUuZGV2MRUwEwYDVQQDEwxzaWdzdG9yZS10c2GgADGCAdwwggHYAgEBMFEwOTEVMBMGA1UEChMMc2lnc3RvcmUuZGV2MSAwHgYDVQQDExdzaWdzdG9yZS10c2Etc2VsZnNpZ25lZAIUOhNULwyQYe68wUMvy4qOiyojiwwwCwYJYIZIAWUDBAIBoIH8MBoGCSqGSIb3DQEJAzENBgsqhkiG9w0BCRABBDAcBgkqhkiG9w0BCQUxDxcNMjYxMDE5MTMxODIzWjAvBgkqhkiG9w0BCQQxIgQgChdtG/mcWGdAqUjlHsL98rTG5klQTLXZofRCueCmlcMwgY4GCyqGSIb3DQEJEAIvMX8wfTB7MHkEIIX5J7wHq2LKw7RDVsEO/IGyxog/2nq55thw2dE6zQW3MFUwPaQ7MDkxFTATBgNVBAoTDHNpZ3N0b3JlLmRldjEgMB4GA1UEAxMXc2lnc3RvcmUtdHNhLXNlbGZzaWduZWQCFDoTVC8MkGHuvMFDL8uKjosqI4sMMAoGCCqGSM49BAMCBGgwZgIxANvTfbN0SFidKmyitQtHD4Zqb8S9dKWiNCxfM34Oh3cGtp11St3BpK8lBFE6kVV5ygIxAPF6xXECkECEvGUpxdM+YCyEz16v/A6sZHjToLqQ52fY6uNObrkl1Lyv7ghcHDtBQQ=="}]}},"messageSignature":{"messageDigest":{"algorithm":"SHA2_256","digest":"DhZeMvnX5xJe0iqv4WXDuxJggY96e1DXpZKKgSmdX0w="},"signature":"MEUCIGuEJYMlfIpfBepj0Su6Nb/31HGbmZng5UFtTj2pY+OIAiEA8GWxD9M9rUuMhwJLUNwDDEGVVTrt1ubPql9IuodyH7o="}}
|
|
|
|
| 1 |
+
{"mediaType":"application/vnd.dev.sigstore.bundle.v0.3+json", "verificationMaterial":{"certificate":{"rawBytes":"MIIHLTCCBrKgAwIBAgIUW8juOVkziLnnecCKBESbrqbEgJEwCgYIKoZIzj0EAwMwNzEVMBMGA1UEChMMc2lnc3RvcmUuZGV2MR4wHAYDVQQDExVzaWdzdG9yZS1pbnRlcm1lZGlhdGUwHhcNMjYxMDIzMTEzNjAyWhcNMjYxMDIzMTE0NjAyWjAAMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEnvx47gGnlRzCN/4OkJ0a7wqYEsIFmCINUHZaFbz5VXCd4BWhf0QldM2OnXd4Ogo0yCWW1dQCX18MRUBj9CRGX6OCBdEwggXNMA4GA1UdDwEB/wQEAwIHgDATBgNVHSUEDDAKBggrBgEFBQcDAzAfBgNVHSMEGDAWgBTf0+nPViQRlvmo2OkoVaLGLhhkPzBrBgNVHREBAf8EYTBfhl1odHRwczovL2dpdGh1Yi5jb20vaHVnZ2luZ2ZhY2Uva2VybmVscy1jb21tdW5pdHkvLmdpdGh1Yi93b3JrZmxvd3MvYnVpbGQueWFtbEByZWZzL2hlYWRzL21haW4wOQYKKwYBBAGDvzABAQQraHR0cHM6Ly90b2tlbi5hY3Rpb25zLmdpdGh1YnVzZXJjb250ZW50LmNvbTAfBgorBgEEAYO/MAECBBF3b3JrZmxvd19kaXNwYXRjaDA2BgorBgEEAYO/MAEDBChmYWE4Njc0NjQ3YWE1ZWJhYWI1ZTk5N2NkMTFlNmUzODA4ZDA5MGE5MBMGCisGAQQBg78wAQQEBUJ1aWxkMCsGCisGAQQBg78wAQUEHWh1Z2dpbmdmYWNlL2tlcm5lbHMtY29tbXVuaXR5MB0GCisGAQQBg78wAQYED3JlZnMvaGVhZHMvbWFpbjA7BgorBgEEAYO/MAEIBC0MK2h0dHBzOi8vdG9rZW4uYWN0aW9ucy5naXRodWJ1c2VyY29udGVudC5jb20wbQYKKwYBBAGDvzABCQRfDF1odHRwczovL2dpdGh1Yi5jb20vaHVnZ2luZ2ZhY2Uva2VybmVscy1jb21tdW5pdHkvLmdpdGh1Yi93b3JrZmxvd3MvYnVpbGQueWFtbEByZWZzL2hlYWRzL21haW4wOAYKKwYBBAGDvzABCgQqDChmYWE4Njc0NjQ3YWE1ZWJhYWI1ZTk5N2NkMTFlNmUzODA4ZDA5MGE5MBsGCisGAQQBg78wAQsEDQwLc2VsZi1ob3N0ZWQwQAYKKwYBBAGDvzABDAQyDDBodHRwczovL2dpdGh1Yi5jb20vaHVnZ2luZ2ZhY2Uva2VybmVscy1jb21tdW5pdHkwOAYKKwYBBAGDvzABDQQqDChmYWE4Njc0NjQ3YWE1ZWJhYWI1ZTk5N2NkMTFlNmUzODA4ZDA5MGE5MB8GCisGAQQBg78wAQ4EEQwPcmVmcy9oZWFkcy9tYWluMBoGCisGAQQBg78wAQ8EDAwKMTA3MTQ3NTUyOTAuBgorBgEEAYO/MAEQBCAMHmh0dHBzOi8vZ2l0aHViLmNvbS9odWdnaW5nZmFjZTAYBgorBgEEAYO/MAERBAoMCDI1NzIwNzQzMG0GCisGAQQBg78wARIEXwxdaHR0cHM6Ly9naXRodWIuY29tL2h1Z2dpbmdmYWNlL2tlcm5lbHMtY29tbXVuaXR5Ly5naXRodWIvd29ya2Zsb3dzL2J1aWxkLnlhbWxAcmVmcy9oZWFkcy9tYWluMDgGCisGAQQBg78wARMEKgwoZmFhODY3NDY0N2FhNWViYWFiNWU5OTdjZDExZTZlMzgwOGQwOTBhOTAhBgorBgEEAYO/MAEUBBMMEXdvcmtmbG93X2Rpc3BhdGNoMGQGCisGAQQBg78wARUEVgxUaHR0cHM6Ly9naXRodWIuY29tL2h1Z2dpbmdmYWNlL2tlcm5lbHMtY29tbXVuaXR5L2FjdGlvbnMvcnVucy8zOTk0NjY4MTMwNi9hdHRlbXB0cy8xMBYGCisGAQQBg78wARYECAwGcHVibGljMEYGCisGAQQBg78wARgEOAw2cmVwbzpodWdnaW5nZmFjZS9rZXJuZWxzLWNvbW11bml0eTpyZWY6cmVmcy9oZWFkcy9tYWluMIGKBgorBgEEAdZ5AgQCBHwEegB4AHYA3T0wasbHETJjGR4cmWc3AqJKXrjePK3/h4pygC8p7o4AAAGhaIvpVQAABAMARzBFAiAoSbfUgNXfezTQtR5qo/CAMwLW8dHV4YbAmcGsMcaFGAIhAMOHSfyt8UUJmPp+JbjTW2xG1BtB/lVIRWOl5oJ/2vZMMAoGCCqGSM49BAMDA2kAMGYCMQCh4ra7/gf8kr1+MdulHjJAXsUd6o0Y9UypE3gFlmHTIgsa/PX9g9NIQP2SRERurOICMQDs43kZxEJ3O3bKz90jbuYM8eNXViJ/TqCHiYc2lWLDQ3rLJWze8xhx7Ks+OwnIgBQ="}, "tlogEntries":[{"logIndex":"3419000459", "logId":{"keyId":"wNI9atQGlz+VWfO6LRygH4QUfY/8W4RFwiT5i5WRgB0="}, "kindVersion":{"kind":"hashedrekord", "version":"0.0.1"}, "integratedTime":"1792755362", "inclusionPromise":{"signedEntryTimestamp":"MEUCICKD7ZdvH1zemVgy07V5zNzmAv0zBIb/8XOEU9QuaaUEAiEAlc/U/9oh4oaQkyOWIzDOALZtdsEroH6lxTDoz9oWPSE="}, "inclusionProof":{"logIndex":"3297096197", "rootHash":"JEwIlEh4C2tvEMwtPOSql67Ts10gAHO7oKqbcfoRsd8=", "treeSize":"3297096204", "hashes":["eKPdjKmW06i/+OgD5Op1qaQr5ljD9icDNR9hKFkKoGs=", "7rIrg/UOeaKdEevZpZHUL3OkluOm/jIeaO923YSkHYo=", "DFFxkRWq9l1mck3McpCgX5nsFudwuRn4U349BXtS7Po=", "S1S/TJWDErr9PeC72czEVORauVEpucJfdtz2vOI5UII=", "06+aOxxaVl4XdwkhaYb3Dh+97wX+oKPonkJn+6nGgmE=", "4iY88O6LVkiDY854scCm32PtSUJYHIsmX33LyfcvBNs=", "DAFTN+3Ntn00j3uqF6DuxpoDvddLg+hpOGsbC8FJr/g=", "sH3iRJ+YSpMgcl9MQvq5mOnxKnX0UOS6Qxva+JrjED8=", "mIjtw1KA13/4jqXfKlJiFrODS7dNF+hqEUNlXprnzTE=", "pNenO6BoAxc3BwcFEO9IJI4uZmwdkynjP9MI8OiYc50=", "1GPTGQWDthSzUsPF7t/XQmpI2SH4KZm3gaVrhMs6T2k=", "YYCr61A8azar3dfO8Ct+pri7LqDxkUlUkfs7fiqYErU=", "1DaDKzrCNNBhmSdY5vFjz+NpAmxmYfYEgBCdPLrMP1A=", "xH/DCseLHr9eKoYT8qsORZK7zVdEGYWHuVtsVrD95wY="], "checkpoint":{"envelope":"rekor.sigstore.dev - 1193050959916656506\n3297096204\nJEwIlEh4C2tvEMwtPOSql67Ts10gAHO7oKqbcfoRsd8=\n\n— rekor.sigstore.dev wNI9ajBFAiEA3J9FLPnuB38IvvWseghTN705Z1/I82uJ9pjXiomV8lcCIF/CifFOxrfvDzHBxDm21wUegDzbni28WhNQ9fftJoeE\n"}}, "canonicalizedBody":"eyJhcGlWZXJzaW9uIjoiMC4wLjEiLCJraW5kIjoiaGFzaGVkcmVrb3JkIiwic3BlYyI6eyJkYXRhIjp7Imhhc2giOnsiYWxnb3JpdGhtIjoic2hhMjU2IiwidmFsdWUiOiIwZGIyMmFhMzI4ZWUzZjcwOTAwYTFmMTM4MzRmYjFiMmFiNDE5NTMwODY0N2MzNWM5NjFmMTAzMGQyNzljMGJhIn19LCJzaWduYXR1cmUiOnsiY29udGVudCI6Ik1FWUNJUURDL2YydTZCS013bFJ5U3Z0RWdUdUsrbUVjTGFQT1lYNmRYUkFwNWdSMytRSWhBS1p3bXRKZ2d2TDNVMEF3SU5kM3NWYXRsN2xCK3oxRjY3V0ptcm1IOVpiQSIsInB1YmxpY0tleSI6eyJjb250ZW50IjoiTFMwdExTMUNSVWRKVGlCRFJWSlVTVVpKUTBGVVJTMHRMUzB0Q2sxSlNVaE1WRU5EUW5KTFowRjNTVUpCWjBsVlZ6aHFkVTlXYTNwcFRHNXVaV05EUzBKRlUySnljV0pGWjBwRmQwTm5XVWxMYjFwSmVtb3dSVUYzVFhjS1RucEZWazFDVFVkQk1WVkZRMmhOVFdNeWJHNWpNMUoyWTIxVmRWcEhWakpOVWpSM1NFRlpSRlpSVVVSRmVGWjZZVmRrZW1SSE9YbGFVekZ3WW01U2JBcGpiVEZzV2tkc2FHUkhWWGRJYUdOT1RXcFplRTFFU1hwTlZFVjZUbXBCZVZkb1kwNU5hbGw0VFVSSmVrMVVSVEJPYWtGNVYycEJRVTFHYTNkRmQxbElDa3R2V2tsNmFqQkRRVkZaU1V0dldrbDZhakJFUVZGalJGRm5RVVZ1ZG5nME4yZEhibXhTZWtOT0x6UlBhMG93WVRkM2NWbEZjMGxHYlVOSlRsVklXbUVLUm1KNk5WWllRMlEwUWxkb1pqQlJiR1JOTWs5dVdHUTBUMmR2TUhsRFYxY3haRkZEV0RFNFRWSlZRbW81UTFKSFdEWlBRMEprUlhkbloxaE9UVUUwUndwQk1WVmtSSGRGUWk5M1VVVkJkMGxJWjBSQlZFSm5UbFpJVTFWRlJFUkJTMEpuWjNKQ1owVkdRbEZqUkVGNlFXWkNaMDVXU0ZOTlJVZEVRVmRuUWxSbUNqQXJibEJXYVZGU2JIWnRiekpQYTI5V1lVeEhUR2hvYTFCNlFuSkNaMDVXU0ZKRlFrRm1PRVZaVkVKbWFHd3hiMlJJVW5kamVtOTJUREprY0dSSGFERUtXV2sxYW1JeU1IWmhTRlp1V2pKc2RWb3lXbWhaTWxWMllUSldlV0p0Vm5OamVURnFZakl4ZEdSWE5YQmtTR3QyVEcxa2NHUkhhREZaYVRrellqTktjZ3BhYlhoMlpETk5kbGx1Vm5CaVIxRjFaVmRHZEdKRlFubGFWMXA2VERKb2JGbFhVbnBNTWpGb1lWYzBkMDlSV1V0TGQxbENRa0ZIUkhaNlFVSkJVVkZ5Q21GSVVqQmpTRTAyVEhrNU1HSXlkR3hpYVRWb1dUTlNjR0l5TlhwTWJXUndaRWRvTVZsdVZucGFXRXBxWWpJMU1GcFhOVEJNYlU1MllsUkJaa0puYjNJS1FtZEZSVUZaVHk5TlFVVkRRa0pHTTJJelNuSmFiWGgyWkRFNWEyRllUbmRaV0ZKcVlVUkJNa0puYjNKQ1owVkZRVmxQTDAxQlJVUkNRMmh0V1ZkRk5BcE9hbU13VG1wUk0xbFhSVEZhVjBwb1dWZEpNVnBVYXpWT01rNXJUVlJHYkU1dFZYcFBSRUUwV2tSQk5VMUhSVFZOUWsxSFEybHpSMEZSVVVKbk56aDNDa0ZSVVVWQ1ZVb3hZVmQ0YTAxRGMwZERhWE5IUVZGUlFtYzNPSGRCVVZWRlNGZG9NVm95WkhCaWJXUnRXVmRPYkV3eWRHeGpiVFZzWWtoTmRGa3lPWFFLWWxoV2RXRllValZOUWpCSFEybHpSMEZSVVVKbk56aDNRVkZaUlVRelNteGFiazEyWVVkV2FGcElUWFppVjBad1ltcEJOMEpuYjNKQ1owVkZRVmxQTHdwTlFVVkpRa013VFVzeWFEQmtTRUo2VDJrNGRtUkhPWEphVnpSMVdWZE9NR0ZYT1hWamVUVnVZVmhTYjJSWFNqRmpNbFo1V1RJNWRXUkhWblZrUXpWcUNtSXlNSGRpVVZsTFMzZFpRa0pCUjBSMmVrRkNRMUZTWmtSR01XOWtTRkozWTNwdmRrd3laSEJrUjJneFdXazFhbUl5TUhaaFNGWnVXakpzZFZveVdtZ0tXVEpWZG1FeVZubGliVlp6WTNreGFtSXlNWFJrVnpWd1pFaHJka3h0WkhCa1IyZ3hXV2s1TTJJelNuSmFiWGgyWkROTmRsbHVWbkJpUjFGMVpWZEdkQXBpUlVKNVdsZGFla3d5YUd4WlYxSjZUREl4YUdGWE5IZFBRVmxMUzNkWlFrSkJSMFIyZWtGQ1EyZFJjVVJEYUcxWlYwVTBUbXBqTUU1cVVUTlpWMFV4Q2xwWFNtaFpWMGt4V2xSck5VNHlUbXROVkVac1RtMVZlazlFUVRSYVJFRTFUVWRGTlUxQ2MwZERhWE5IUVZGUlFtYzNPSGRCVVhORlJGRjNUR015Vm5NS1dta3hiMkl6VGpCYVYxRjNVVUZaUzB0M1dVSkNRVWRFZG5wQlFrUkJVWGxFUkVKdlpFaFNkMk42YjNaTU1tUndaRWRvTVZscE5XcGlNakIyWVVoV2JncGFNbXgxV2pKYWFGa3lWWFpoTWxaNVltMVdjMk41TVdwaU1qRjBaRmMxY0dSSWEzZFBRVmxMUzNkWlFrSkJSMFIyZWtGQ1JGRlJjVVJEYUcxWlYwVTBDazVxWXpCT2FsRXpXVmRGTVZwWFNtaFpWMGt4V2xSck5VNHlUbXROVkVac1RtMVZlazlFUVRSYVJFRTFUVWRGTlUxQ09FZERhWE5IUVZGUlFtYzNPSGNLUVZFMFJVVlJkMUJqYlZadFkzazViMXBYUm10amVUbDBXVmRzZFUxQ2IwZERhWE5IUVZGUlFtYzNPSGRCVVRoRlJFRjNTMDFVUVROTlZGRXpUbFJWZVFwUFZFRjFRbWR2Y2tKblJVVkJXVTh2VFVGRlVVSkRRVTFJYldnd1pFaENlazlwT0haYU1td3dZVWhXYVV4dFRuWmlVemx2WkZka2JtRlhOVzVhYlVacUNscFVRVmxDWjI5eVFtZEZSVUZaVHk5TlFVVlNRa0Z2VFVORVNURk9la2wzVG5wUmVrMUhNRWREYVhOSFFWRlJRbWMzT0hkQlVrbEZXSGQ0WkdGSVVqQUtZMGhOTmt4NU9XNWhXRkp2WkZkSmRWa3lPWFJNTW1neFdqSmtjR0p0WkcxWlYwNXNUREowYkdOdE5XeGlTRTEwV1RJNWRHSllWblZoV0ZJMVRIazFiZ3BoV0ZKdlpGZEpkbVF5T1hsaE1scHpZak5rZWt3eVNqRmhWM2hyVEc1c2FHSlhlRUZqYlZadFkzazViMXBYUm10amVUbDBXVmRzZFUxRVowZERhWE5IQ2tGUlVVSm5OemgzUVZKTlJVdG5kMjlhYlVab1QwUlpNMDVFV1RCT01rWm9UbGRXYVZsWFJtbE9WMVUxVDFSa2FscEVSWGhhVkZwc1RYcG5kMDlIVVhjS1QxUkNhRTlVUVdoQ1oyOXlRbWRGUlVGWlR5OU5RVVZWUWtKTlRVVllaSFpqYlhSdFlrYzVNMWd5VW5Cak0wSm9aRWRPYjAxSFVVZERhWE5IUVZGUlFncG5OemgzUVZKVlJWWm5lRlZoU0ZJd1kwaE5Oa3g1T1c1aFdGSnZaRmRKZFZreU9YUk1NbWd4V2pKa2NHSnRaRzFaVjA1c1RESjBiR050Tld4aVNFMTBDbGt5T1hSaVdGWjFZVmhTTlV3eVJtcGtSMngyWW01TmRtTnVWblZqZVRoNlQxUnJNRTVxV1RSTlZFMTNUbWs1YUdSSVVteGlXRUl3WTNrNGVFMUNXVWNLUTJselIwRlJVVUpuTnpoM1FWSlpSVU5CZDBkalNGWnBZa2RzYWsxRldVZERhWE5IUVZGUlFtYzNPSGRCVW1kRlQwRjNNbU50Vm5kaWVuQnZaRmRrYmdwaFZ6VnVXbTFHYWxwVE9YSmFXRXAxV2xkNGVreFhUblppVnpFeFltMXNNR1ZVY0hsYVYxazJZMjFXYldONU9XOWFWMFpyWTNrNWRGbFhiSFZOU1VkTENrSm5iM0pDWjBWRlFXUmFOVUZuVVVOQ1NIZEZaV2RDTkVGSVdVRXpWREIzWVhOaVNFVlVTbXBIVWpSamJWZGpNMEZ4U2t0WWNtcGxVRXN6TDJnMGNIa0taME00Y0Rkdk5FRkJRVWRvWVVsMmNGWlJRVUZDUVUxQlVucENSa0ZwUVc5VFltWlZaMDVZWm1WNlZGRjBValZ4Ynk5RFFVMTNURmM0WkVoV05GbGlRUXB0WTBkelRXTmhSa2RCU1doQlRVOUlVMlo1ZERoVlZVcHRVSEFyU21KcVZGY3llRWN4UW5SQ0wyeFdTVkpYVDJ3MWIwb3ZNblphVFUxQmIwZERRM0ZIQ2xOTk5EbENRVTFFUVRKclFVMUhXVU5OVVVOb05ISmhOeTluWmpocmNqRXJUV1IxYkVocVNrRlljMVZrTm04d1dUbFZlWEJGTTJkR2JHMUlWRWxuYzJFS0wxQllPV2M1VGtsUlVESlRVa1ZTZFhKUFNVTk5VVVJ6TkROclduaEZTak5QTTJKTGVqa3dhbUoxV1UwNFpVNVlWbWxLTDFSeFEwaHBXV015YkZkTVJBcFJNM0pNU2xkNlpUaDRhSGczUzNNclQzZHVTV2RDVVQwS0xTMHRMUzFGVGtRZ1EwVlNWRWxHU1VOQlZFVXRMUzB0TFFvPSJ9fX19"}], "timestampVerificationData":{"rfc3161Timestamps":[{"signedTimestamp":"MIICyzADAgEAMIICwgYJKoZIhvcNAQcCoIICszCCAq8CAQMxDTALBglghkgBZQMEAgEwgbgGCyqGSIb3DQEJEAEEoIGoBIGlMIGiAgEBBgkrBgEEAYO/MAIwMTANBglghkgBZQMEAgEFAAQg3bpS2VtJbbj+NwI4jCmvshiu/17s+rjceNrg2WK85ewCFQC8epRj5pgyFllwm2wpZ1CZZQQv6hgPMjAyNjEwMjMxMTM2MDJaMAMCAQGgMqQwMC4xFTATBgNVBAoTDHNpZ3N0b3JlLmRldjEVMBMGA1UEAxMMc2lnc3RvcmUtdHNhoAAxggHcMIIB2AIBATBRMDkxFTATBgNVBAoTDHNpZ3N0b3JlLmRldjEgMB4GA1UEAxMXc2lnc3RvcmUtdHNhLXNlbGZzaWduZWQCFDoTVC8MkGHuvMFDL8uKjosqI4sMMAsGCWCGSAFlAwQCAaCB/DAaBgkqhkiG9w0BCQMxDQYLKoZIhvcNAQkQAQQwHAYJKoZIhvcNAQkFMQ8XDTI2MTAyMzExMzYwMlowLwYJKoZIhvcNAQkEMSIEICpkIWImbVOed+fyc52Sr18JzDELBbbea0FI1ljUg31hMIGOBgsqhkiG9w0BCRACLzF/MH0wezB5BCCF+Se8B6tiysO0Q1bBDvyBssaIP9p6uebYcNnROs0FtzBVMD2kOzA5MRUwEwYDVQQKEwxzaWdzdG9yZS5kZXYxIDAeBgNVBAMTF3NpZ3N0b3JlLXRzYS1zZWxmc2lnbmVkAhQ6E1QvDJBh7rzBQy/Lio6LKiOLDDAKBggqhkjOPQQDAgRoMGYCMQD2N3QvdKUrb7mICl3pBDsE03F8HuaqvKzbzOufuc/onqDuhozEGeCO7WtAfnBimSYCMQDaZJiF4IvNVlXG7SnHGbx6kg6iHsKj9VRRlszRA/TNd923wrJtH7f1Kck8QNXzJgU="}]}}, "messageSignature":{"messageDigest":{"algorithm":"SHA2_256", "digest":"DbIqoyjuP3CQCh8Tg0+xsqtBlTCGR8Nclh8QMNJ5wLo="}, "signature":"MEYCIQDC/f2u6BKMwlRySvtEgTuK+mEcLaPOYX6dXRAp5gR3+QIhAKZwmtJggvL3U0AwINd3sVatl7lB+z1F67WJmrmH9ZbA"}}
|
build/torch-cuda/modules/__init__.py
CHANGED
|
@@ -5,25 +5,106 @@
|
|
| 5 |
# For a list of all contributors, visit:
|
| 6 |
# https://github.com/fla-org/flash-linear-attention/graphs/contributors
|
| 7 |
|
| 8 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 9 |
from ..modules.fused_bitlinear import BitLinear, FusedBitLinear
|
| 10 |
from ..modules.fused_cross_entropy import FusedCrossEntropyLoss
|
| 11 |
from ..modules.fused_kl_div import FusedKLDivLoss
|
| 12 |
from ..modules.fused_linear_cross_entropy import FusedLinearCrossEntropyLoss
|
| 13 |
-
from ..modules.
|
|
|
|
|
|
|
| 14 |
FusedLayerNormGated,
|
| 15 |
FusedLayerNormSwishGate,
|
| 16 |
FusedLayerNormSwishGateLinear,
|
| 17 |
FusedRMSNormGated,
|
| 18 |
FusedRMSNormSwishGate,
|
| 19 |
FusedRMSNormSwishGateLinear,
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 20 |
)
|
| 21 |
-
from ..modules.l2norm import L2Norm
|
| 22 |
-
from ..modules.layernorm import GroupNorm, GroupNormLinear, LayerNorm, LayerNormLinear, RMSNorm, RMSNormLinear
|
| 23 |
-
from ..modules.mlp import GatedMLP
|
| 24 |
from ..modules.rotary import RotaryEmbedding
|
| 25 |
from ..modules.token_shift import TokenShift
|
| 26 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 27 |
__all__ = [
|
| 28 |
'BitLinear',
|
| 29 |
'FusedBitLinear',
|
|
|
|
| 5 |
# For a list of all contributors, visit:
|
| 6 |
# https://github.com/fla-org/flash-linear-attention/graphs/contributors
|
| 7 |
|
| 8 |
+
import sys
|
| 9 |
+
from importlib import import_module
|
| 10 |
+
from importlib.machinery import ModuleSpec
|
| 11 |
+
from types import ModuleType
|
| 12 |
+
|
| 13 |
+
from ..modules.causal_conv1d import ShortConvolution
|
| 14 |
from ..modules.fused_bitlinear import BitLinear, FusedBitLinear
|
| 15 |
from ..modules.fused_cross_entropy import FusedCrossEntropyLoss
|
| 16 |
from ..modules.fused_kl_div import FusedKLDivLoss
|
| 17 |
from ..modules.fused_linear_cross_entropy import FusedLinearCrossEntropyLoss
|
| 18 |
+
from ..modules.long_conv import ImplicitLongConvolution, LongConvolution
|
| 19 |
+
from ..modules.mlp import GatedMLP
|
| 20 |
+
from ..modules.norm import (
|
| 21 |
FusedLayerNormGated,
|
| 22 |
FusedLayerNormSwishGate,
|
| 23 |
FusedLayerNormSwishGateLinear,
|
| 24 |
FusedRMSNormGated,
|
| 25 |
FusedRMSNormSwishGate,
|
| 26 |
FusedRMSNormSwishGateLinear,
|
| 27 |
+
GroupNorm,
|
| 28 |
+
GroupNormLinear,
|
| 29 |
+
L2Norm,
|
| 30 |
+
LayerNorm,
|
| 31 |
+
LayerNormLinear,
|
| 32 |
+
RMSNorm,
|
| 33 |
+
RMSNormLinear,
|
| 34 |
)
|
|
|
|
|
|
|
|
|
|
| 35 |
from ..modules.rotary import RotaryEmbedding
|
| 36 |
from ..modules.token_shift import TokenShift
|
| 37 |
|
| 38 |
+
_MODULE_ALIASES = {
|
| 39 |
+
'fused_norm_gate': ('norm.fused_norm_gate',),
|
| 40 |
+
'l2norm': ('norm.l2norm',),
|
| 41 |
+
'layernorm': ('norm.layernorm',),
|
| 42 |
+
'layernorm_gated': ('norm.layernorm_gated',),
|
| 43 |
+
'convolution': ('causal_conv1d', 'long_conv', 'causal_conv1d.cp', 'causal_conv1d.backends.cuda'),
|
| 44 |
+
'conv': ('causal_conv1d', 'long_conv'),
|
| 45 |
+
'conv.causal_conv1d': ('causal_conv1d.ops',),
|
| 46 |
+
'conv.short_conv': ('causal_conv1d.ops',),
|
| 47 |
+
'conv.long_conv': ('long_conv',),
|
| 48 |
+
'conv.cp': ('causal_conv1d.cp',),
|
| 49 |
+
'conv.cp.ops': ('causal_conv1d.cp',),
|
| 50 |
+
'conv.cuda': ('causal_conv1d.backends.cuda',),
|
| 51 |
+
'conv.cuda.ops': ('causal_conv1d.backends.cuda.ops',),
|
| 52 |
+
'conv.triton': ('causal_conv1d.ops',),
|
| 53 |
+
'conv.triton.ops': ('causal_conv1d.ops',),
|
| 54 |
+
'conv.triton.kernels': ('causal_conv1d.ops',),
|
| 55 |
+
}
|
| 56 |
+
|
| 57 |
+
for _old, _targets in _MODULE_ALIASES.items():
|
| 58 |
+
_fullname = f'{__name__}.{_old}'
|
| 59 |
+
if len(_targets) == 1:
|
| 60 |
+
_module = import_module(f'{__name__}.{_targets[0]}')
|
| 61 |
+
else:
|
| 62 |
+
_module = ModuleType(_fullname)
|
| 63 |
+
_module.__spec__ = ModuleSpec(_fullname, loader=None, is_package=True)
|
| 64 |
+
_module.__path__ = []
|
| 65 |
+
for _target in _targets:
|
| 66 |
+
_source = import_module(f'{__name__}.{_target}')
|
| 67 |
+
for _symbol in getattr(_source, '__all__', vars(_source)):
|
| 68 |
+
if not _symbol.startswith('_'):
|
| 69 |
+
vars(_module).setdefault(_symbol, getattr(_source, _symbol))
|
| 70 |
+
_module.__all__ = [name for name in vars(_module) if not name.startswith('_')]
|
| 71 |
+
sys.modules[_fullname] = _module
|
| 72 |
+
# conv.causal_conv1d is a function on the old package.
|
| 73 |
+
if _old != 'conv.causal_conv1d':
|
| 74 |
+
_parent, _, _child = _fullname.rpartition('.')
|
| 75 |
+
setattr(sys.modules[_parent], _child, _module)
|
| 76 |
+
|
| 77 |
+
# defer GRPO's compile policy until it is explicitly imported
|
| 78 |
+
for _name in ('activations', 'rotary', 'fused_cross_entropy', 'fused_kl_div', 'fused_linear_cross_entropy'):
|
| 79 |
+
_module = import_module(f'{__name__}.{_name}')
|
| 80 |
+
for _symbol, _value in vars(import_module(f'{__name__}.{_name}.ops')).items():
|
| 81 |
+
if not _symbol.startswith('_'):
|
| 82 |
+
vars(_module).setdefault(_symbol, _value)
|
| 83 |
+
|
| 84 |
+
_SYMBOL_ALIASES = {
|
| 85 |
+
'fused_bitlinear': {
|
| 86 |
+
'layer_norm_fwd_quant': 'norm.layernorm_quant.layer_norm_quant_fwd',
|
| 87 |
+
'layer_norm_bwd': 'norm.layernorm_quant.layer_norm_quant_bwd',
|
| 88 |
+
'LayerNormLinearQuantFn': 'LayerNormLinearQuantFunction',
|
| 89 |
+
'layer_norm_linear_quant_fn': 'layer_norm_linear_quant',
|
| 90 |
+
},
|
| 91 |
+
'fused_cross_entropy': {
|
| 92 |
+
'fused_cross_entropy_forward': 'cross_entropy_fwd',
|
| 93 |
+
'CrossEntropyLossFunction': 'FusedCrossEntropyFunction',
|
| 94 |
+
},
|
| 95 |
+
'fused_kl_div': {'fused_kl_div_forward': 'fused_kl_div_fwd', 'fused_kl_div_backward': 'fused_kl_div_bwd'},
|
| 96 |
+
'fused_linear_cross_entropy': {
|
| 97 |
+
'fused_linear_cross_entropy_forward': 'fused_linear_cross_entropy_fwd',
|
| 98 |
+
'fused_linear_cross_entropy_backward': 'fused_linear_cross_entropy_bwd',
|
| 99 |
+
},
|
| 100 |
+
}
|
| 101 |
+
for _name, _aliases in _SYMBOL_ALIASES.items():
|
| 102 |
+
_module = sys.modules[f'{__name__}.{_name}']
|
| 103 |
+
for _old, _new in _aliases.items():
|
| 104 |
+
_target, _, _symbol = _new.rpartition('.')
|
| 105 |
+
_source = import_module(f'{__name__}.{_target}') if _target else _module
|
| 106 |
+
setattr(_module, _old, getattr(_source, _symbol))
|
| 107 |
+
|
| 108 |
__all__ = [
|
| 109 |
'BitLinear',
|
| 110 |
'FusedBitLinear',
|
build/{torch-xpu/ops/cp → torch-cuda/modules/activations}/__init__.py
RENAMED
|
@@ -5,28 +5,35 @@
|
|
| 5 |
# For a list of all contributors, visit:
|
| 6 |
# https://github.com/fla-org/flash-linear-attention/graphs/contributors
|
| 7 |
|
| 8 |
-
|
| 9 |
-
|
| 10 |
-
|
| 11 |
-
|
| 12 |
-
|
| 13 |
-
|
| 14 |
-
|
| 15 |
-
|
| 16 |
-
|
| 17 |
-
|
| 18 |
-
|
| 19 |
-
|
| 20 |
-
|
|
|
|
| 21 |
)
|
| 22 |
|
| 23 |
__all__ = [
|
| 24 |
-
|
| 25 |
-
|
| 26 |
-
|
| 27 |
-
|
| 28 |
-
|
| 29 |
-
|
| 30 |
-
|
| 31 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 32 |
]
|
|
|
|
|
|
| 5 |
# For a list of all contributors, visit:
|
| 6 |
# https://github.com/fla-org/flash-linear-attention/graphs/contributors
|
| 7 |
|
| 8 |
+
from ...modules.activations.ops import (
|
| 9 |
+
ACT2FN,
|
| 10 |
+
elu_p1,
|
| 11 |
+
fast_gelu_impl,
|
| 12 |
+
logsigmoid,
|
| 13 |
+
powglu,
|
| 14 |
+
powglu_linear,
|
| 15 |
+
sigmoid,
|
| 16 |
+
sigmoidglu,
|
| 17 |
+
sigmoidglu_linear,
|
| 18 |
+
sqrelu,
|
| 19 |
+
swiglu,
|
| 20 |
+
swiglu_linear,
|
| 21 |
+
swish,
|
| 22 |
)
|
| 23 |
|
| 24 |
__all__ = [
|
| 25 |
+
'ACT2FN',
|
| 26 |
+
'elu_p1',
|
| 27 |
+
'fast_gelu_impl',
|
| 28 |
+
'logsigmoid',
|
| 29 |
+
'powglu',
|
| 30 |
+
'powglu_linear',
|
| 31 |
+
'sigmoid',
|
| 32 |
+
'sigmoidglu',
|
| 33 |
+
'sigmoidglu_linear',
|
| 34 |
+
'sqrelu',
|
| 35 |
+
'swiglu',
|
| 36 |
+
'swiglu_linear',
|
| 37 |
+
'swish',
|
| 38 |
]
|
| 39 |
+
|
build/torch-cuda/modules/{activations.py → activations/ops.py}
RENAMED
|
@@ -8,43 +8,58 @@
|
|
| 8 |
"""Fused activation kernels.
|
| 9 |
|
| 10 |
The kernels address their inputs through the row stride instead of assuming a fully contiguous buffer.
|
| 11 |
-
An inner-contiguous input — such as one half of ``x.chunk(2, dim=-1)`` — is therefore read in place,
|
| 12 |
-
``.contiguous()`` copy
|
| 13 |
"""
|
| 14 |
|
| 15 |
import torch
|
| 16 |
import torch.nn.functional as F
|
| 17 |
import triton
|
| 18 |
import triton.language as tl
|
| 19 |
-
|
| 20 |
-
|
| 21 |
-
from ..
|
| 22 |
-
from ..utils import
|
| 23 |
-
|
| 24 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 25 |
|
| 26 |
|
| 27 |
def _get_stride(x: torch.Tensor) -> int:
|
| 28 |
"""Get the row stride for viewing a tensor as 2D (num_rows, D) where D = shape[-1].
|
| 29 |
|
| 30 |
Returns stride(-2) if the tensor is at least 2D, or 0 for 1D tensors.
|
| 31 |
-
The caller must ensure
|
| 32 |
-
higher dims are contiguous relative to dim -2) before using this value.
|
| 33 |
"""
|
| 34 |
if x.ndim < 2:
|
| 35 |
return 0
|
|
|
|
|
|
|
| 36 |
return x.stride(-2)
|
| 37 |
|
| 38 |
|
| 39 |
def _is_inner_contiguous(x: torch.Tensor) -> bool:
|
| 40 |
"""Check if a tensor can be safely viewed as 2D (num_rows, D) with row stride = stride(-2).
|
| 41 |
|
| 42 |
-
This holds when stride(-1) == 1 and all dimensions above -2 are contiguous
|
| 43 |
-
with respect to the dimension below them.
|
| 44 |
"""
|
| 45 |
ndim = x.ndim
|
| 46 |
if ndim < 2:
|
| 47 |
-
return
|
| 48 |
if x.stride(-1) != 1:
|
| 49 |
return False
|
| 50 |
if ndim == 2:
|
|
@@ -69,7 +84,9 @@ def _is_inner_contiguous(x: torch.Tensor) -> bool:
|
|
| 69 |
|
| 70 |
def _ensure_inner_contiguous(x: torch.Tensor) -> torch.Tensor:
|
| 71 |
"""Make the tensor inner-contiguous if it isn't already."""
|
| 72 |
-
if
|
|
|
|
|
|
|
| 73 |
return x
|
| 74 |
return x.contiguous()
|
| 75 |
|
|
@@ -77,32 +94,17 @@ def _ensure_inner_contiguous(x: torch.Tensor) -> torch.Tensor:
|
|
| 77 |
def _alloc_output(x: torch.Tensor, contiguous: bool = False) -> torch.Tensor:
|
| 78 |
"""Allocate the output: a fresh contiguous buffer, or ``empty_like`` otherwise.
|
| 79 |
|
| 80 |
-
``empty_like`` keeps the input's memory format only when it is dense;
|
| 81 |
-
strided view (e.g. a ``chunk`` slice) falls back to contiguous, not the input stride.
|
| 82 |
"""
|
| 83 |
if contiguous:
|
| 84 |
return x.new_empty(x.shape)
|
| 85 |
return torch.empty_like(x)
|
| 86 |
|
| 87 |
|
| 88 |
-
@triton.autotune(
|
| 89 |
-
configs=[
|
| 90 |
-
triton.Config({'B': bs}, num_warps=num_warps)
|
| 91 |
-
for bs in [512, 1024, 2048, 4096, 8192]
|
| 92 |
-
for num_warps in NUM_WARPS_AUTOTUNE
|
| 93 |
-
],
|
| 94 |
-
key=['D'],
|
| 95 |
-
**autotune_cache_kwargs,
|
| 96 |
-
)
|
| 97 |
@triton.jit(do_not_specialize=['T'])
|
| 98 |
-
def sigmoid_fwd_kernel(
|
| 99 |
-
x, y,
|
| 100 |
-
stride_x_row,
|
| 101 |
-
stride_y_row,
|
| 102 |
-
T,
|
| 103 |
-
D: tl.constexpr,
|
| 104 |
-
B: tl.constexpr,
|
| 105 |
-
):
|
| 106 |
i_n = tl.program_id(0).to(tl.int64)
|
| 107 |
offs = i_n * B + tl.arange(0, B)
|
| 108 |
mask = offs < T
|
|
@@ -113,25 +115,9 @@ def sigmoid_fwd_kernel(
|
|
| 113 |
tl.store(y + row * stride_y_row + col, b_y.to(y.dtype.element_ty), mask=mask)
|
| 114 |
|
| 115 |
|
| 116 |
-
@triton.autotune(
|
| 117 |
-
configs=[
|
| 118 |
-
triton.Config({'B': bs}, num_warps=num_warps)
|
| 119 |
-
for bs in [512, 1024, 2048, 4096, 8192]
|
| 120 |
-
for num_warps in NUM_WARPS_AUTOTUNE
|
| 121 |
-
],
|
| 122 |
-
key=['D'],
|
| 123 |
-
**autotune_cache_kwargs,
|
| 124 |
-
)
|
| 125 |
@triton.jit(do_not_specialize=['T'])
|
| 126 |
-
def sigmoid_bwd_kernel(
|
| 127 |
-
x, dy, dx,
|
| 128 |
-
stride_x_row,
|
| 129 |
-
stride_dy_row,
|
| 130 |
-
stride_dx_row,
|
| 131 |
-
T,
|
| 132 |
-
D: tl.constexpr,
|
| 133 |
-
B: tl.constexpr,
|
| 134 |
-
):
|
| 135 |
i_n = tl.program_id(0).to(tl.int64)
|
| 136 |
offs = i_n * B + tl.arange(0, B)
|
| 137 |
mask = offs < T
|
|
@@ -144,35 +130,35 @@ def sigmoid_bwd_kernel(
|
|
| 144 |
tl.store(dx + row * stride_dx_row + col, b_dx.to(dx.dtype.element_ty), mask=mask)
|
| 145 |
|
| 146 |
|
| 147 |
-
@dispatch
|
| 148 |
def sigmoid_fwd(x: torch.Tensor, output_contiguous: bool = False) -> torch.Tensor:
|
| 149 |
-
x = _ensure_inner_contiguous(x)
|
| 150 |
T, D = x.numel(), x.shape[-1]
|
| 151 |
-
y = _alloc_output(x, output_contiguous)
|
| 152 |
sigmoid_fwd_kernel[lambda meta: (triton.cdiv(T, meta['B']),)](
|
| 153 |
x=x,
|
| 154 |
y=y,
|
| 155 |
-
stride_x_row=_get_stride(x),
|
| 156 |
-
stride_y_row=_get_stride(y),
|
| 157 |
T=T,
|
| 158 |
D=D,
|
| 159 |
)
|
| 160 |
return y
|
| 161 |
|
| 162 |
|
| 163 |
-
@dispatch
|
| 164 |
def sigmoid_bwd(x: torch.Tensor, dy: torch.Tensor, output_contiguous: bool = False) -> torch.Tensor:
|
| 165 |
-
x = _ensure_inner_contiguous(x)
|
| 166 |
-
dy = _ensure_inner_contiguous(dy)
|
| 167 |
T, D = x.numel(), x.shape[-1]
|
| 168 |
-
dx = _alloc_output(x, output_contiguous)
|
| 169 |
sigmoid_bwd_kernel[lambda meta: (triton.cdiv(T, meta['B']),)](
|
| 170 |
x=x,
|
| 171 |
dy=dy,
|
| 172 |
dx=dx,
|
| 173 |
-
stride_x_row=_get_stride(x),
|
| 174 |
-
stride_dy_row=_get_stride(dy),
|
| 175 |
-
stride_dx_row=_get_stride(dx),
|
| 176 |
T=T,
|
| 177 |
D=D,
|
| 178 |
)
|
|
@@ -185,38 +171,111 @@ class SigmoidFunction(torch.autograd.Function):
|
|
| 185 |
@input_guard(no_guard_contiguous=True)
|
| 186 |
def forward(ctx, x):
|
| 187 |
ctx.save_for_backward(x)
|
| 188 |
-
return sigmoid_fwd(x)
|
| 189 |
|
| 190 |
@staticmethod
|
| 191 |
@input_guard(no_guard_contiguous=True)
|
| 192 |
def backward(ctx, dout):
|
| 193 |
x, = ctx.saved_tensors
|
| 194 |
-
return sigmoid_bwd(x, dout)
|
| 195 |
|
| 196 |
|
| 197 |
sigmoid = SigmoidFunction.apply
|
| 198 |
|
| 199 |
|
| 200 |
-
@triton.autotune(
|
| 201 |
-
configs=[
|
| 202 |
-
triton.Config({'B': bs}, num_warps=num_warps)
|
| 203 |
-
for bs in [512, 1024, 2048, 4096, 8192]
|
| 204 |
-
for num_warps in NUM_WARPS_AUTOTUNE
|
| 205 |
-
],
|
| 206 |
-
key=['D'],
|
| 207 |
-
**autotune_cache_kwargs,
|
| 208 |
-
)
|
| 209 |
@triton.jit(do_not_specialize=['T'])
|
| 210 |
-
def
|
| 211 |
-
|
| 212 |
-
|
| 213 |
-
|
| 214 |
-
|
| 215 |
-
|
| 216 |
-
|
| 217 |
-
|
| 218 |
-
|
| 219 |
-
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 220 |
i_n = tl.program_id(0).to(tl.int64)
|
| 221 |
offs = i_n * B + tl.arange(0, B)
|
| 222 |
mask = offs < T
|
|
@@ -229,15 +288,7 @@ def logsigmoid_fwd_kernel(
|
|
| 229 |
tl.store(y + row * stride_y_row + col, b_y.to(y.dtype.element_ty), mask=mask)
|
| 230 |
|
| 231 |
|
| 232 |
-
@triton.autotune(
|
| 233 |
-
configs=[
|
| 234 |
-
triton.Config({'B': bs}, num_warps=num_warps)
|
| 235 |
-
for bs in [512, 1024, 2048, 4096, 8192]
|
| 236 |
-
for num_warps in NUM_WARPS_AUTOTUNE
|
| 237 |
-
],
|
| 238 |
-
key=['D'],
|
| 239 |
-
**autotune_cache_kwargs,
|
| 240 |
-
)
|
| 241 |
@triton.jit(do_not_specialize=['T'])
|
| 242 |
def logsigmoid_bwd_kernel(
|
| 243 |
x,
|
|
@@ -262,16 +313,16 @@ def logsigmoid_bwd_kernel(
|
|
| 262 |
tl.store(dx + row * stride_dx_row + col, b_dx.to(dx.dtype.element_ty), mask=mask)
|
| 263 |
|
| 264 |
|
| 265 |
-
@dispatch
|
| 266 |
def logsigmoid_fwd(x: torch.Tensor, temperature: float = 1., output_contiguous: bool = False) -> torch.Tensor:
|
| 267 |
-
x = _ensure_inner_contiguous(x)
|
| 268 |
T, D = x.numel(), x.shape[-1]
|
| 269 |
-
y = _alloc_output(x, output_contiguous)
|
| 270 |
logsigmoid_fwd_kernel[lambda meta: (triton.cdiv(T, meta['B']),)](
|
| 271 |
x=x,
|
| 272 |
y=y,
|
| 273 |
-
stride_x_row=_get_stride(x),
|
| 274 |
-
stride_y_row=_get_stride(y),
|
| 275 |
temperature=temperature,
|
| 276 |
T=T,
|
| 277 |
D=D,
|
|
@@ -279,24 +330,24 @@ def logsigmoid_fwd(x: torch.Tensor, temperature: float = 1., output_contiguous:
|
|
| 279 |
return y
|
| 280 |
|
| 281 |
|
| 282 |
-
@dispatch
|
| 283 |
def logsigmoid_bwd(
|
| 284 |
x: torch.Tensor,
|
| 285 |
dy: torch.Tensor,
|
| 286 |
temperature: float = 1.,
|
| 287 |
output_contiguous: bool = False,
|
| 288 |
) -> torch.Tensor:
|
| 289 |
-
x = _ensure_inner_contiguous(x)
|
| 290 |
-
dy = _ensure_inner_contiguous(dy)
|
| 291 |
T, D = x.numel(), x.shape[-1]
|
| 292 |
-
dx = _alloc_output(x, output_contiguous)
|
| 293 |
logsigmoid_bwd_kernel[lambda meta: (triton.cdiv(T, meta['B']),)](
|
| 294 |
x=x,
|
| 295 |
dy=dy,
|
| 296 |
dx=dx,
|
| 297 |
-
stride_x_row=_get_stride(x),
|
| 298 |
-
stride_dy_row=_get_stride(dy),
|
| 299 |
-
stride_dx_row=_get_stride(dx),
|
| 300 |
temperature=temperature,
|
| 301 |
T=T,
|
| 302 |
D=D,
|
|
@@ -311,37 +362,22 @@ class LogSigmoidFunction(torch.autograd.Function):
|
|
| 311 |
def forward(ctx, x, temperature):
|
| 312 |
ctx.save_for_backward(x)
|
| 313 |
ctx.temperature = temperature
|
| 314 |
-
return logsigmoid_fwd(x, temperature)
|
| 315 |
|
| 316 |
@staticmethod
|
| 317 |
@input_guard(no_guard_contiguous=True)
|
| 318 |
def backward(ctx, dy):
|
| 319 |
x, = ctx.saved_tensors
|
| 320 |
-
return logsigmoid_bwd(x, dy, ctx.temperature), None
|
| 321 |
|
| 322 |
|
| 323 |
def logsigmoid(x: torch.Tensor, temperature: float = 1.) -> torch.Tensor:
|
| 324 |
return LogSigmoidFunction.apply(x, temperature)
|
| 325 |
|
| 326 |
|
| 327 |
-
@triton.autotune(
|
| 328 |
-
configs=[
|
| 329 |
-
triton.Config({'B': bs}, num_warps=num_warps)
|
| 330 |
-
for bs in [512, 1024, 2048, 4096, 8192]
|
| 331 |
-
for num_warps in NUM_WARPS_AUTOTUNE
|
| 332 |
-
],
|
| 333 |
-
key=['D'],
|
| 334 |
-
**autotune_cache_kwargs,
|
| 335 |
-
)
|
| 336 |
@triton.jit(do_not_specialize=['T'])
|
| 337 |
-
def swish_fwd_kernel(
|
| 338 |
-
x, y,
|
| 339 |
-
stride_x_row,
|
| 340 |
-
stride_y_row,
|
| 341 |
-
T,
|
| 342 |
-
D: tl.constexpr,
|
| 343 |
-
B: tl.constexpr,
|
| 344 |
-
):
|
| 345 |
i_n = tl.program_id(0).to(tl.int64)
|
| 346 |
offs = i_n * B + tl.arange(0, B)
|
| 347 |
mask = offs < T
|
|
@@ -352,25 +388,9 @@ def swish_fwd_kernel(
|
|
| 352 |
tl.store(y + row * stride_y_row + col, b_y.to(y.dtype.element_ty), mask=mask)
|
| 353 |
|
| 354 |
|
| 355 |
-
@triton.autotune(
|
| 356 |
-
configs=[
|
| 357 |
-
triton.Config({'B': bs}, num_warps=num_warps)
|
| 358 |
-
for bs in [512, 1024, 2048, 4096, 8192]
|
| 359 |
-
for num_warps in NUM_WARPS_AUTOTUNE
|
| 360 |
-
],
|
| 361 |
-
key=['D'],
|
| 362 |
-
**autotune_cache_kwargs,
|
| 363 |
-
)
|
| 364 |
@triton.jit(do_not_specialize=['T'])
|
| 365 |
-
def swish_bwd_kernel(
|
| 366 |
-
x, dy, dx,
|
| 367 |
-
stride_x_row,
|
| 368 |
-
stride_dy_row,
|
| 369 |
-
stride_dx_row,
|
| 370 |
-
T,
|
| 371 |
-
D: tl.constexpr,
|
| 372 |
-
B: tl.constexpr,
|
| 373 |
-
):
|
| 374 |
i_n = tl.program_id(0).to(tl.int64)
|
| 375 |
offs = i_n * B + tl.arange(0, B)
|
| 376 |
mask = offs < T
|
|
@@ -383,35 +403,35 @@ def swish_bwd_kernel(
|
|
| 383 |
tl.store(dx + row * stride_dx_row + col, b_dx.to(dx.dtype.element_ty), mask=mask)
|
| 384 |
|
| 385 |
|
| 386 |
-
@dispatch
|
| 387 |
def swish_fwd(x: torch.Tensor, output_contiguous: bool = False) -> torch.Tensor:
|
| 388 |
-
x = _ensure_inner_contiguous(x)
|
| 389 |
T, D = x.numel(), x.shape[-1]
|
| 390 |
-
y = _alloc_output(x, output_contiguous)
|
| 391 |
swish_fwd_kernel[lambda meta: (triton.cdiv(T, meta['B']),)](
|
| 392 |
x=x,
|
| 393 |
y=y,
|
| 394 |
-
stride_x_row=_get_stride(x),
|
| 395 |
-
stride_y_row=_get_stride(y),
|
| 396 |
T=T,
|
| 397 |
D=D,
|
| 398 |
)
|
| 399 |
return y
|
| 400 |
|
| 401 |
|
| 402 |
-
@dispatch
|
| 403 |
def swish_bwd(x: torch.Tensor, dy: torch.Tensor, output_contiguous: bool = False) -> torch.Tensor:
|
| 404 |
-
x = _ensure_inner_contiguous(x)
|
| 405 |
-
dy = _ensure_inner_contiguous(dy)
|
| 406 |
T, D = x.numel(), x.shape[-1]
|
| 407 |
-
dx = _alloc_output(x, output_contiguous)
|
| 408 |
swish_bwd_kernel[lambda meta: (triton.cdiv(T, meta['B']),)](
|
| 409 |
x=x,
|
| 410 |
dy=dy,
|
| 411 |
dx=dx,
|
| 412 |
-
stride_x_row=_get_stride(x),
|
| 413 |
-
stride_dy_row=_get_stride(dy),
|
| 414 |
-
stride_dx_row=_get_stride(dx),
|
| 415 |
T=T,
|
| 416 |
D=D,
|
| 417 |
)
|
|
@@ -424,13 +444,13 @@ class SwishFunction(torch.autograd.Function):
|
|
| 424 |
@input_guard(no_guard_contiguous=True)
|
| 425 |
def forward(ctx, x):
|
| 426 |
ctx.save_for_backward(x)
|
| 427 |
-
return swish_fwd(x)
|
| 428 |
|
| 429 |
@staticmethod
|
| 430 |
@input_guard(no_guard_contiguous=True)
|
| 431 |
def backward(ctx, dout):
|
| 432 |
x, = ctx.saved_tensors
|
| 433 |
-
return swish_bwd(x, dout)
|
| 434 |
|
| 435 |
|
| 436 |
swish = SwishFunction.apply
|
|
@@ -440,27 +460,20 @@ swish = SwishFunction.apply
|
|
| 440 |
# sqrt(2/pi) -> 0.79788456
|
| 441 |
|
| 442 |
|
| 443 |
-
#
|
| 444 |
-
# actual gelu is:
|
| 445 |
-
# x * 0.5 * (1.0 + torch.erf(x * 0.70710678))
|
| 446 |
@torch.compile
|
| 447 |
def bias_gelu(y, bias):
|
| 448 |
x = bias + y
|
| 449 |
return (x * 0.5 * (1.0 + torch.tanh(0.79788456 * x * (1 + 0.044715 * x * x)))).to(dtype=y.dtype)
|
| 450 |
|
| 451 |
|
| 452 |
-
# gradient of tanh approximation of gelu
|
| 453 |
-
# gradient of actual gelu is:
|
| 454 |
-
# 0.5 * (1. + torch.erf(x * 0.70710678)) + 0.3989423 * x * torch.exp(-0.5 * x * x)
|
| 455 |
@torch.compile
|
| 456 |
def bias_gelu_bwd(g, y, bias):
|
| 457 |
-
"""
|
| 458 |
x = bias + y
|
| 459 |
tanh_out = torch.tanh(0.79788456 * x * (1 + 0.044715 * x * x))
|
| 460 |
# sqrt(2/pi) * 3 * 0.044715 -> 0.1070322243
|
| 461 |
-
ff = 0.5 * x * ((1 - tanh_out * tanh_out) * (0.79788456 + 0.1070322243 * x * x)) + 0.5 * (
|
| 462 |
-
1 + tanh_out
|
| 463 |
-
)
|
| 464 |
grad_y = ff * g
|
| 465 |
return grad_y.to(dtype=y.dtype), grad_y.sum(dim=(0), dtype=bias.dtype)
|
| 466 |
|
|
@@ -468,54 +481,43 @@ def bias_gelu_bwd(g, y, bias):
|
|
| 468 |
class GeLUFunction(torch.autograd.Function):
|
| 469 |
|
| 470 |
@staticmethod
|
| 471 |
-
# bias is an optional argument
|
| 472 |
def forward(ctx, input, bias):
|
| 473 |
ctx.save_for_backward(input, bias)
|
| 474 |
-
return bias_gelu(input, bias)
|
| 475 |
|
| 476 |
@staticmethod
|
| 477 |
def backward(ctx, grad_output):
|
| 478 |
input, bias = ctx.saved_tensors
|
| 479 |
-
return bias_gelu_bwd(grad_output, input, bias)
|
| 480 |
|
| 481 |
|
| 482 |
bias_gelu_impl = GeLUFunction.apply
|
| 483 |
|
| 484 |
|
| 485 |
-
#
|
| 486 |
-
# actual gelu is:
|
| 487 |
-
# x * 0.5 * (1.0 + torch.erf(x * 0.70710678))
|
| 488 |
-
@dispatch('modules')
|
| 489 |
@torch.compile
|
| 490 |
def gelu_fwd(x):
|
| 491 |
return (x * 0.5 * (1.0 + torch.tanh(0.79788456 * x * (1 + 0.044715 * x * x)))).to(dtype=x.dtype)
|
| 492 |
|
| 493 |
|
| 494 |
-
# gradient of tanh approximation of gelu
|
| 495 |
-
# gradient of actual gelu is:
|
| 496 |
-
# 0.5 * (1. + torch.erf(x * 0.70710678)) + 0.3989423 * x * torch.exp(-0.5 * x * x)
|
| 497 |
-
@dispatch('modules')
|
| 498 |
@torch.compile
|
| 499 |
def gelu_bwd(g, x):
|
| 500 |
tanh_out = torch.tanh(0.79788456 * x * (1 + 0.044715 * x * x))
|
| 501 |
# sqrt(2/pi) * 3 * 0.044715 -> 0.1070322243
|
| 502 |
-
ff = 0.5 * x * ((1 - tanh_out * tanh_out) * (0.79788456 + 0.1070322243 * x * x)) + 0.5 * (
|
| 503 |
-
1 + tanh_out
|
| 504 |
-
)
|
| 505 |
return (ff * g).to(dtype=x.dtype)
|
| 506 |
|
| 507 |
|
| 508 |
class FastGeLUFunction(torch.autograd.Function):
|
| 509 |
@staticmethod
|
| 510 |
-
# bias is an optional argument
|
| 511 |
def forward(ctx, input):
|
| 512 |
ctx.save_for_backward(input)
|
| 513 |
-
return gelu_fwd(input)
|
| 514 |
|
| 515 |
@staticmethod
|
| 516 |
def backward(ctx, grad_output):
|
| 517 |
(input,) = ctx.saved_tensors
|
| 518 |
-
tmp = gelu_bwd(grad_output, input)
|
| 519 |
return tmp
|
| 520 |
|
| 521 |
|
|
@@ -527,14 +529,12 @@ def relu_bwd(g, x):
|
|
| 527 |
return torch.where(x >= 0, g, 0.0).to(dtype=x.dtype)
|
| 528 |
|
| 529 |
|
| 530 |
-
@dispatch('modules')
|
| 531 |
@torch.compile
|
| 532 |
def sqrelu_fwd(x):
|
| 533 |
r = F.relu(x.float())
|
| 534 |
return (r * r).to(dtype=x.dtype)
|
| 535 |
|
| 536 |
|
| 537 |
-
@dispatch('modules')
|
| 538 |
@torch.compile
|
| 539 |
def sqrelu_bwd(g, x):
|
| 540 |
return (2.0 * g * F.relu(x.float())).to(dtype=x.dtype)
|
|
@@ -545,36 +545,20 @@ class SquaredReLUFunction(torch.autograd.Function):
|
|
| 545 |
@staticmethod
|
| 546 |
def forward(ctx, input):
|
| 547 |
ctx.save_for_backward(input)
|
| 548 |
-
return sqrelu_fwd(input)
|
| 549 |
|
| 550 |
@staticmethod
|
| 551 |
def backward(ctx, grad_output):
|
| 552 |
input, = ctx.saved_tensors
|
| 553 |
-
return sqrelu_bwd(grad_output, input)
|
| 554 |
|
| 555 |
|
| 556 |
sqrelu = SquaredReLUFunction.apply
|
| 557 |
|
| 558 |
|
| 559 |
-
@triton.autotune(
|
| 560 |
-
configs=[
|
| 561 |
-
triton.Config({'B': bs}, num_warps=num_warps)
|
| 562 |
-
for bs in [512, 1024, 2048, 4096, 8192]
|
| 563 |
-
for num_warps in NUM_WARPS_AUTOTUNE
|
| 564 |
-
],
|
| 565 |
-
key=['D'],
|
| 566 |
-
**autotune_cache_kwargs,
|
| 567 |
-
)
|
| 568 |
@triton.jit(do_not_specialize=['T'])
|
| 569 |
-
def swiglu_fwd_kernel(
|
| 570 |
-
x, y, z,
|
| 571 |
-
stride_x_row,
|
| 572 |
-
stride_y_row,
|
| 573 |
-
stride_z_row,
|
| 574 |
-
T,
|
| 575 |
-
D: tl.constexpr,
|
| 576 |
-
B: tl.constexpr,
|
| 577 |
-
):
|
| 578 |
i_n = tl.program_id(0).to(tl.int64)
|
| 579 |
offs = i_n * B + tl.arange(0, B)
|
| 580 |
mask = offs < T
|
|
@@ -586,21 +570,16 @@ def swiglu_fwd_kernel(
|
|
| 586 |
tl.store(z + row * stride_z_row + col, b_z.to(z.dtype.element_ty), mask=mask)
|
| 587 |
|
| 588 |
|
| 589 |
-
@triton.heuristics({
|
| 590 |
-
|
| 591 |
-
})
|
| 592 |
-
@triton.autotune(
|
| 593 |
-
configs=[
|
| 594 |
-
triton.Config({'B': bs}, num_warps=num_warps)
|
| 595 |
-
for bs in [512, 1024, 2048, 4096, 8192]
|
| 596 |
-
for num_warps in NUM_WARPS_AUTOTUNE
|
| 597 |
-
],
|
| 598 |
-
key=['D'],
|
| 599 |
-
**autotune_cache_kwargs,
|
| 600 |
-
)
|
| 601 |
@triton.jit(do_not_specialize=['T'])
|
| 602 |
def swiglu_fwdbwd_kernel(
|
| 603 |
-
x,
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 604 |
stride_x_row,
|
| 605 |
stride_y_row,
|
| 606 |
stride_g_row,
|
|
@@ -633,27 +612,27 @@ def swiglu_fwdbwd_kernel(
|
|
| 633 |
tl.store(z + row * stride_z_row + col, b_z.to(z.dtype.element_ty), mask=mask)
|
| 634 |
|
| 635 |
|
| 636 |
-
@dispatch
|
| 637 |
def swiglu_fwd(x: torch.Tensor, y: torch.Tensor, output_contiguous: bool = False) -> torch.Tensor:
|
| 638 |
assert x.shape == y.shape, f"swiglu_fwd: shape mismatch x={x.shape} y={y.shape}"
|
| 639 |
-
x = _ensure_inner_contiguous(x)
|
| 640 |
-
y = _ensure_inner_contiguous(y)
|
| 641 |
T, D = x.numel(), x.shape[-1]
|
| 642 |
-
z = _alloc_output(x, output_contiguous)
|
| 643 |
swiglu_fwd_kernel[lambda meta: (triton.cdiv(T, meta['B']),)](
|
| 644 |
x=x,
|
| 645 |
y=y,
|
| 646 |
z=z,
|
| 647 |
-
stride_x_row=_get_stride(x),
|
| 648 |
-
stride_y_row=_get_stride(y),
|
| 649 |
-
stride_z_row=_get_stride(z),
|
| 650 |
T=T,
|
| 651 |
D=D,
|
| 652 |
)
|
| 653 |
return z
|
| 654 |
|
| 655 |
|
| 656 |
-
@dispatch
|
| 657 |
def swiglu_fwdbwd(
|
| 658 |
x: torch.Tensor,
|
| 659 |
y: torch.Tensor,
|
|
@@ -662,14 +641,14 @@ def swiglu_fwdbwd(
|
|
| 662 |
output_contiguous: bool = False,
|
| 663 |
):
|
| 664 |
assert x.shape == y.shape == g.shape, f"swiglu_fwdbwd: shape mismatch x={x.shape} y={y.shape} g={g.shape}"
|
| 665 |
-
x = _ensure_inner_contiguous(x)
|
| 666 |
-
y = _ensure_inner_contiguous(y)
|
| 667 |
-
g = _ensure_inner_contiguous(g)
|
| 668 |
T, D = x.numel(), x.shape[-1]
|
| 669 |
-
dx = _alloc_output(x, output_contiguous)
|
| 670 |
-
dy = _alloc_output(y, output_contiguous)
|
| 671 |
if use_weight:
|
| 672 |
-
z = _alloc_output(x, output_contiguous)
|
| 673 |
else:
|
| 674 |
z = None
|
| 675 |
swiglu_fwdbwd_kernel[lambda meta: (triton.cdiv(T, meta['B']),)](
|
|
@@ -679,12 +658,12 @@ def swiglu_fwdbwd(
|
|
| 679 |
dx=dx,
|
| 680 |
dy=dy,
|
| 681 |
z=z,
|
| 682 |
-
stride_x_row=_get_stride(x),
|
| 683 |
-
stride_y_row=_get_stride(y),
|
| 684 |
-
stride_g_row=_get_stride(g),
|
| 685 |
-
stride_dx_row=_get_stride(dx),
|
| 686 |
-
stride_dy_row=_get_stride(dy),
|
| 687 |
-
stride_z_row=_get_stride(z) if z is not None else 0,
|
| 688 |
T=T,
|
| 689 |
D=D,
|
| 690 |
)
|
|
@@ -705,13 +684,13 @@ class SwiGLUFunction(torch.autograd.Function):
|
|
| 705 |
@input_guard(no_guard_contiguous=True)
|
| 706 |
def forward(ctx, x, y):
|
| 707 |
ctx.save_for_backward(x, y)
|
| 708 |
-
return swiglu_fwd(x, y)
|
| 709 |
|
| 710 |
@staticmethod
|
| 711 |
@input_guard(no_guard_contiguous=True)
|
| 712 |
def backward(ctx, dout):
|
| 713 |
x, y = ctx.saved_tensors
|
| 714 |
-
return swiglu_fwdbwd(x, y, dout)
|
| 715 |
|
| 716 |
|
| 717 |
class SwiGLULinearFunction(torch.autograd.Function):
|
|
@@ -728,10 +707,9 @@ class SwiGLULinearFunction(torch.autograd.Function):
|
|
| 728 |
@input_guard(no_guard_contiguous=True)
|
| 729 |
@autocast_custom_fwd
|
| 730 |
def forward(ctx, x, y, weight, bias):
|
| 731 |
-
z = swiglu_fwd(x, y, output_contiguous=True)
|
| 732 |
out = F.linear(z, weight, bias)
|
| 733 |
ctx.save_for_backward(x, y, weight)
|
| 734 |
-
ctx.linear_bias_is_none = bias is None
|
| 735 |
return out
|
| 736 |
|
| 737 |
@staticmethod
|
|
@@ -740,40 +718,32 @@ class SwiGLULinearFunction(torch.autograd.Function):
|
|
| 740 |
def backward(ctx, dout, *args):
|
| 741 |
x, y, weight = ctx.saved_tensors
|
| 742 |
dout = dout.reshape(-1, dout.shape[-1])
|
| 743 |
-
|
| 744 |
-
|
| 745 |
-
|
| 746 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 747 |
return dx, dy, dlinear_weight, dlinear_bias
|
| 748 |
|
| 749 |
|
| 750 |
swiglu = SwiGLUFunction.apply
|
| 751 |
|
| 752 |
|
| 753 |
-
@dispatch
|
| 754 |
def swiglu_linear(x, y, weight, bias):
|
| 755 |
return SwiGLULinearFunction.apply(x, y, weight, bias)
|
| 756 |
|
| 757 |
|
| 758 |
-
@triton.autotune(
|
| 759 |
-
configs=[
|
| 760 |
-
triton.Config({'B': bs}, num_warps=num_warps)
|
| 761 |
-
for bs in [512, 1024, 2048, 4096, 8192]
|
| 762 |
-
for num_warps in NUM_WARPS_AUTOTUNE
|
| 763 |
-
],
|
| 764 |
-
key=['D'],
|
| 765 |
-
**autotune_cache_kwargs,
|
| 766 |
-
)
|
| 767 |
@triton.jit(do_not_specialize=['T'])
|
| 768 |
-
def sigmoidglu_fwd_kernel(
|
| 769 |
-
x, y, z,
|
| 770 |
-
stride_x_row,
|
| 771 |
-
stride_y_row,
|
| 772 |
-
stride_z_row,
|
| 773 |
-
T,
|
| 774 |
-
D: tl.constexpr,
|
| 775 |
-
B: tl.constexpr,
|
| 776 |
-
):
|
| 777 |
i_n = tl.program_id(0).to(tl.int64)
|
| 778 |
offs = i_n * B + tl.arange(0, B)
|
| 779 |
mask = offs < T
|
|
@@ -785,21 +755,16 @@ def sigmoidglu_fwd_kernel(
|
|
| 785 |
tl.store(z + row * stride_z_row + col, b_z.to(z.dtype.element_ty), mask=mask)
|
| 786 |
|
| 787 |
|
| 788 |
-
@triton.heuristics({
|
| 789 |
-
|
| 790 |
-
})
|
| 791 |
-
@triton.autotune(
|
| 792 |
-
configs=[
|
| 793 |
-
triton.Config({'B': bs}, num_warps=num_warps)
|
| 794 |
-
for bs in [512, 1024, 2048, 4096, 8192]
|
| 795 |
-
for num_warps in NUM_WARPS_AUTOTUNE
|
| 796 |
-
],
|
| 797 |
-
key=['D'],
|
| 798 |
-
**autotune_cache_kwargs,
|
| 799 |
-
)
|
| 800 |
@triton.jit(do_not_specialize=['T'])
|
| 801 |
def sigmoidglu_fwdbwd_kernel(
|
| 802 |
-
x,
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 803 |
stride_x_row,
|
| 804 |
stride_y_row,
|
| 805 |
stride_g_row,
|
|
@@ -834,17 +799,17 @@ def sigmoidglu_fwdbwd_kernel(
|
|
| 834 |
@torch.compiler.disable
|
| 835 |
def sigmoidglu_fwd(x: torch.Tensor, y: torch.Tensor, output_contiguous: bool = False) -> torch.Tensor:
|
| 836 |
assert x.shape == y.shape, f"sigmoidglu_fwd: shape mismatch x={x.shape} y={y.shape}"
|
| 837 |
-
x = _ensure_inner_contiguous(x)
|
| 838 |
-
y = _ensure_inner_contiguous(y)
|
| 839 |
T, D = x.numel(), x.shape[-1]
|
| 840 |
-
z = _alloc_output(x, output_contiguous)
|
| 841 |
sigmoidglu_fwd_kernel[lambda meta: (triton.cdiv(T, meta['B']),)](
|
| 842 |
x=x,
|
| 843 |
y=y,
|
| 844 |
z=z,
|
| 845 |
-
stride_x_row=_get_stride(x),
|
| 846 |
-
stride_y_row=_get_stride(y),
|
| 847 |
-
stride_z_row=_get_stride(z),
|
| 848 |
T=T,
|
| 849 |
D=D,
|
| 850 |
)
|
|
@@ -860,14 +825,14 @@ def sigmoidglu_fwdbwd(
|
|
| 860 |
output_contiguous: bool = False,
|
| 861 |
):
|
| 862 |
assert x.shape == y.shape == g.shape, f"sigmoidglu_fwdbwd: shape mismatch x={x.shape} y={y.shape} g={g.shape}"
|
| 863 |
-
x = _ensure_inner_contiguous(x)
|
| 864 |
-
y = _ensure_inner_contiguous(y)
|
| 865 |
-
g = _ensure_inner_contiguous(g)
|
| 866 |
T, D = x.numel(), x.shape[-1]
|
| 867 |
-
dx = _alloc_output(x, output_contiguous)
|
| 868 |
-
dy = _alloc_output(y, output_contiguous)
|
| 869 |
if use_weight:
|
| 870 |
-
z = _alloc_output(x, output_contiguous)
|
| 871 |
else:
|
| 872 |
z = None
|
| 873 |
sigmoidglu_fwdbwd_kernel[lambda meta: (triton.cdiv(T, meta['B']),)](
|
|
@@ -877,12 +842,12 @@ def sigmoidglu_fwdbwd(
|
|
| 877 |
dx=dx,
|
| 878 |
dy=dy,
|
| 879 |
z=z,
|
| 880 |
-
stride_x_row=_get_stride(x),
|
| 881 |
-
stride_y_row=_get_stride(y),
|
| 882 |
-
stride_g_row=_get_stride(g),
|
| 883 |
-
stride_dx_row=_get_stride(dx),
|
| 884 |
-
stride_dy_row=_get_stride(dy),
|
| 885 |
-
stride_z_row=_get_stride(z) if z is not None else 0,
|
| 886 |
T=T,
|
| 887 |
D=D,
|
| 888 |
)
|
|
@@ -903,13 +868,13 @@ class SigmoidGLUFunction(torch.autograd.Function):
|
|
| 903 |
@input_guard(no_guard_contiguous=True)
|
| 904 |
def forward(ctx, x, y):
|
| 905 |
ctx.save_for_backward(x, y)
|
| 906 |
-
return sigmoidglu_fwd(x, y)
|
| 907 |
|
| 908 |
@staticmethod
|
| 909 |
@input_guard(no_guard_contiguous=True)
|
| 910 |
def backward(ctx, dout):
|
| 911 |
x, y = ctx.saved_tensors
|
| 912 |
-
return sigmoidglu_fwdbwd(x, y, dout)
|
| 913 |
|
| 914 |
|
| 915 |
class SigmoidGLULinearFunction(torch.autograd.Function):
|
|
@@ -926,7 +891,7 @@ class SigmoidGLULinearFunction(torch.autograd.Function):
|
|
| 926 |
@input_guard(no_guard_contiguous=True)
|
| 927 |
@autocast_custom_fwd
|
| 928 |
def forward(ctx, x, y, weight, bias):
|
| 929 |
-
z = sigmoidglu_fwd(x, y, output_contiguous=True)
|
| 930 |
out = F.linear(z, weight, bias)
|
| 931 |
ctx.save_for_backward(x, y, weight)
|
| 932 |
ctx.linear_bias_is_none = bias is None
|
|
@@ -939,7 +904,7 @@ class SigmoidGLULinearFunction(torch.autograd.Function):
|
|
| 939 |
x, y, weight = ctx.saved_tensors
|
| 940 |
dout = dout.reshape(-1, dout.shape[-1])
|
| 941 |
dz = F.linear(dout, weight.t()).view_as(x)
|
| 942 |
-
dx, dy, z = sigmoidglu_fwdbwd(x, y, dz, use_weight=True, output_contiguous=True)
|
| 943 |
dlinear_weight = torch.einsum("bo,bi->oi", dout, z.reshape(-1, z.shape[-1]))
|
| 944 |
dlinear_bias = None if ctx.linear_bias_is_none else dout.sum(0)
|
| 945 |
return dx, dy, dlinear_weight, dlinear_bias
|
|
@@ -951,26 +916,9 @@ sigmoidglu = SigmoidGLUFunction.apply
|
|
| 951 |
sigmoidglu_linear = SigmoidGLULinearFunction.apply
|
| 952 |
|
| 953 |
|
| 954 |
-
@triton.autotune(
|
| 955 |
-
configs=[
|
| 956 |
-
triton.Config({'B': bs}, num_warps=num_warps)
|
| 957 |
-
for bs in [512, 1024, 2048, 4096, 8192]
|
| 958 |
-
for num_warps in NUM_WARPS_AUTOTUNE
|
| 959 |
-
],
|
| 960 |
-
key=['D'],
|
| 961 |
-
**autotune_cache_kwargs,
|
| 962 |
-
)
|
| 963 |
@triton.jit(do_not_specialize=['T'])
|
| 964 |
-
def powglu_fwd_kernel(
|
| 965 |
-
x, y, z,
|
| 966 |
-
stride_x_row,
|
| 967 |
-
stride_y_row,
|
| 968 |
-
stride_z_row,
|
| 969 |
-
m,
|
| 970 |
-
T,
|
| 971 |
-
D: tl.constexpr,
|
| 972 |
-
B: tl.constexpr,
|
| 973 |
-
):
|
| 974 |
i_n = tl.program_id(0).to(tl.int64)
|
| 975 |
offs = i_n * B + tl.arange(0, B)
|
| 976 |
mask = offs < T
|
|
@@ -990,21 +938,16 @@ def powglu_fwd_kernel(
|
|
| 990 |
tl.store(z + row * stride_z_row + col, b_z.to(z.dtype.element_ty), mask=mask)
|
| 991 |
|
| 992 |
|
| 993 |
-
@triton.heuristics({
|
| 994 |
-
|
| 995 |
-
})
|
| 996 |
-
@triton.autotune(
|
| 997 |
-
configs=[
|
| 998 |
-
triton.Config({'B': bs}, num_warps=num_warps)
|
| 999 |
-
for bs in [512, 1024, 2048, 4096, 8192]
|
| 1000 |
-
for num_warps in NUM_WARPS_AUTOTUNE
|
| 1001 |
-
],
|
| 1002 |
-
key=['D'],
|
| 1003 |
-
**autotune_cache_kwargs,
|
| 1004 |
-
)
|
| 1005 |
@triton.jit(do_not_specialize=['T'])
|
| 1006 |
def powglu_fwdbwd_kernel(
|
| 1007 |
-
x,
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1008 |
stride_x_row,
|
| 1009 |
stride_y_row,
|
| 1010 |
stride_g_row,
|
|
@@ -1054,20 +997,20 @@ def powglu_fwdbwd_kernel(
|
|
| 1054 |
tl.store(z + row * stride_z_row + col, b_z.to(z.dtype.element_ty), mask=mask)
|
| 1055 |
|
| 1056 |
|
| 1057 |
-
@dispatch
|
| 1058 |
def powglu_fwd(x: torch.Tensor, y: torch.Tensor, power: float = 3.0, output_contiguous: bool = False) -> torch.Tensor:
|
| 1059 |
assert x.shape == y.shape, f"powglu_fwd: shape mismatch x={x.shape} y={y.shape}"
|
| 1060 |
-
x = _ensure_inner_contiguous(x)
|
| 1061 |
-
y = _ensure_inner_contiguous(y)
|
| 1062 |
T, D = x.numel(), x.shape[-1]
|
| 1063 |
-
z = _alloc_output(x, output_contiguous)
|
| 1064 |
powglu_fwd_kernel[lambda meta: (triton.cdiv(T, meta['B']),)](
|
| 1065 |
x=x,
|
| 1066 |
y=y,
|
| 1067 |
z=z,
|
| 1068 |
-
stride_x_row=_get_stride(x),
|
| 1069 |
-
stride_y_row=_get_stride(y),
|
| 1070 |
-
stride_z_row=_get_stride(z),
|
| 1071 |
m=power,
|
| 1072 |
T=T,
|
| 1073 |
D=D,
|
|
@@ -1075,7 +1018,7 @@ def powglu_fwd(x: torch.Tensor, y: torch.Tensor, power: float = 3.0, output_cont
|
|
| 1075 |
return z
|
| 1076 |
|
| 1077 |
|
| 1078 |
-
@dispatch
|
| 1079 |
def powglu_fwdbwd(
|
| 1080 |
x: torch.Tensor,
|
| 1081 |
y: torch.Tensor,
|
|
@@ -1085,14 +1028,14 @@ def powglu_fwdbwd(
|
|
| 1085 |
output_contiguous: bool = False,
|
| 1086 |
):
|
| 1087 |
assert x.shape == y.shape == g.shape, f"powglu_fwdbwd: shape mismatch x={x.shape} y={y.shape} g={g.shape}"
|
| 1088 |
-
x = _ensure_inner_contiguous(x)
|
| 1089 |
-
y = _ensure_inner_contiguous(y)
|
| 1090 |
-
g = _ensure_inner_contiguous(g)
|
| 1091 |
T, D = x.numel(), x.shape[-1]
|
| 1092 |
-
dx = _alloc_output(x, output_contiguous)
|
| 1093 |
-
dy = _alloc_output(y, output_contiguous)
|
| 1094 |
if use_weight:
|
| 1095 |
-
z = _alloc_output(x, output_contiguous)
|
| 1096 |
else:
|
| 1097 |
z = None
|
| 1098 |
powglu_fwdbwd_kernel[lambda meta: (triton.cdiv(T, meta['B']),)](
|
|
@@ -1102,12 +1045,12 @@ def powglu_fwdbwd(
|
|
| 1102 |
dx=dx,
|
| 1103 |
dy=dy,
|
| 1104 |
z=z,
|
| 1105 |
-
stride_x_row=_get_stride(x),
|
| 1106 |
-
stride_y_row=_get_stride(y),
|
| 1107 |
-
stride_g_row=_get_stride(g),
|
| 1108 |
-
stride_dx_row=_get_stride(dx),
|
| 1109 |
-
stride_dy_row=_get_stride(dy),
|
| 1110 |
-
stride_z_row=_get_stride(z) if z is not None else 0,
|
| 1111 |
m=power,
|
| 1112 |
T=T,
|
| 1113 |
D=D,
|
|
@@ -1125,8 +1068,8 @@ class PowGLUFunction(torch.autograd.Function):
|
|
| 1125 |
\text{PowGLU}(x, y) = g(x) * y,\quad
|
| 1126 |
g(x) = \begin{cases} x^{power/(\sqrt{x}+1)}\,\sigma(x) & x > 0 \\ x\,\sigma(x) & x \le 0 \end{cases}
|
| 1127 |
|
| 1128 |
-
For ``x <= 0`` the gate reduces to swish, matching SwiGLU; for large ``x > 0`` it saturates instead of
|
| 1129 |
-
|
| 1130 |
"""
|
| 1131 |
|
| 1132 |
@staticmethod
|
|
@@ -1134,13 +1077,13 @@ class PowGLUFunction(torch.autograd.Function):
|
|
| 1134 |
def forward(ctx, x, y, power):
|
| 1135 |
ctx.save_for_backward(x, y)
|
| 1136 |
ctx.power = power
|
| 1137 |
-
return powglu_fwd(x, y, power)
|
| 1138 |
|
| 1139 |
@staticmethod
|
| 1140 |
@input_guard(no_guard_contiguous=True)
|
| 1141 |
def backward(ctx, dout):
|
| 1142 |
x, y = ctx.saved_tensors
|
| 1143 |
-
dx, dy = powglu_fwdbwd(x, y, dout, ctx.power)
|
| 1144 |
return dx, dy, None
|
| 1145 |
|
| 1146 |
|
|
@@ -1158,7 +1101,7 @@ class PowGLULinearFunction(torch.autograd.Function):
|
|
| 1158 |
@input_guard(no_guard_contiguous=True)
|
| 1159 |
@autocast_custom_fwd
|
| 1160 |
def forward(ctx, x, y, weight, bias, power):
|
| 1161 |
-
z = powglu_fwd(x, y, power, output_contiguous=True)
|
| 1162 |
out = F.linear(z, weight, bias)
|
| 1163 |
ctx.save_for_backward(x, y, weight)
|
| 1164 |
ctx.linear_bias_is_none = bias is None
|
|
@@ -1172,7 +1115,7 @@ class PowGLULinearFunction(torch.autograd.Function):
|
|
| 1172 |
x, y, weight = ctx.saved_tensors
|
| 1173 |
dout = dout.reshape(-1, dout.shape[-1])
|
| 1174 |
dz = F.linear(dout, weight.t()).view_as(x)
|
| 1175 |
-
dx, dy, z = powglu_fwdbwd(x, y, dz, ctx.power, use_weight=True, output_contiguous=True)
|
| 1176 |
dlinear_weight = torch.einsum("bo,bi->oi", dout, z.reshape(-1, z.shape[-1]))
|
| 1177 |
dlinear_bias = None if ctx.linear_bias_is_none else dout.sum(0)
|
| 1178 |
return dx, dy, dlinear_weight, dlinear_bias, None
|
|
@@ -1182,7 +1125,7 @@ def powglu(x: torch.Tensor, y: torch.Tensor, power: float = 3.0) -> torch.Tensor
|
|
| 1182 |
return PowGLUFunction.apply(x, y, power)
|
| 1183 |
|
| 1184 |
|
| 1185 |
-
@dispatch
|
| 1186 |
def powglu_linear(
|
| 1187 |
x: torch.Tensor,
|
| 1188 |
y: torch.Tensor,
|
|
|
|
| 8 |
"""Fused activation kernels.
|
| 9 |
|
| 10 |
The kernels address their inputs through the row stride instead of assuming a fully contiguous buffer.
|
| 11 |
+
An inner-contiguous input — such as one half of ``x.chunk(2, dim=-1)`` — is therefore read in place,
|
| 12 |
+
avoiding the ``.contiguous()`` copy and memory traffic that a flat element-wise kernel would require on every call.
|
| 13 |
"""
|
| 14 |
|
| 15 |
import torch
|
| 16 |
import torch.nn.functional as F
|
| 17 |
import triton
|
| 18 |
import triton.language as tl
|
| 19 |
+
from triton.language.extra import libdevice
|
| 20 |
+
|
| 21 |
+
from ...backends import dispatch
|
| 22 |
+
from ...ops.utils.op import exp, log
|
| 23 |
+
from ...utils import IS_AMD, IS_INTEL, IS_NPU, autocast_custom_bwd, autocast_custom_fwd, autotune_cache_kwargs, input_guard
|
| 24 |
+
|
| 25 |
+
|
| 26 |
+
def _activation_autotune_configs():
|
| 27 |
+
"""Return autotune configs scaled to the device's scratch-space budget."""
|
| 28 |
+
if IS_INTEL:
|
| 29 |
+
# Intel/XPU has a smaller per-thread scratch space (PTSS) limit; smaller
|
| 30 |
+
# block sizes and warp counts avoid register spilling on larger D.
|
| 31 |
+
bs_list = [512, 1024]
|
| 32 |
+
nw_list = [1, 2, 4, 8]
|
| 33 |
+
elif IS_AMD:
|
| 34 |
+
bs_list = [512, 1024, 2048, 4096, 8192]
|
| 35 |
+
nw_list = [1, 2, 4, 8, 16]
|
| 36 |
+
else:
|
| 37 |
+
bs_list = [512, 1024, 2048, 4096, 8192]
|
| 38 |
+
nw_list = [1, 2, 4, 8, 16, 32]
|
| 39 |
+
return [triton.Config({'B': bs}, num_warps=nw) for bs in bs_list for nw in nw_list]
|
| 40 |
|
| 41 |
|
| 42 |
def _get_stride(x: torch.Tensor) -> int:
|
| 43 |
"""Get the row stride for viewing a tensor as 2D (num_rows, D) where D = shape[-1].
|
| 44 |
|
| 45 |
Returns stride(-2) if the tensor is at least 2D, or 0 for 1D tensors.
|
| 46 |
+
The caller must ensure stride(-1) == 1, with higher dimensions contiguous relative to dimension -2.
|
|
|
|
| 47 |
"""
|
| 48 |
if x.ndim < 2:
|
| 49 |
return 0
|
| 50 |
+
if torch.compiler.is_compiling():
|
| 51 |
+
return x.shape[-1]
|
| 52 |
return x.stride(-2)
|
| 53 |
|
| 54 |
|
| 55 |
def _is_inner_contiguous(x: torch.Tensor) -> bool:
|
| 56 |
"""Check if a tensor can be safely viewed as 2D (num_rows, D) with row stride = stride(-2).
|
| 57 |
|
| 58 |
+
This holds when stride(-1) == 1 and all dimensions above -2 are contiguous with respect to the dimension below them.
|
|
|
|
| 59 |
"""
|
| 60 |
ndim = x.ndim
|
| 61 |
if ndim < 2:
|
| 62 |
+
return x.is_contiguous()
|
| 63 |
if x.stride(-1) != 1:
|
| 64 |
return False
|
| 65 |
if ndim == 2:
|
|
|
|
| 84 |
|
| 85 |
def _ensure_inner_contiguous(x: torch.Tensor) -> torch.Tensor:
|
| 86 |
"""Make the tensor inner-contiguous if it isn't already."""
|
| 87 |
+
if torch.compiler.is_compiling():
|
| 88 |
+
return x.contiguous()
|
| 89 |
+
if _is_inner_contiguous(x=x):
|
| 90 |
return x
|
| 91 |
return x.contiguous()
|
| 92 |
|
|
|
|
| 94 |
def _alloc_output(x: torch.Tensor, contiguous: bool = False) -> torch.Tensor:
|
| 95 |
"""Allocate the output: a fresh contiguous buffer, or ``empty_like`` otherwise.
|
| 96 |
|
| 97 |
+
``empty_like`` keeps the input's memory format only when it is dense;
|
| 98 |
+
a non-dense strided view (e.g. a ``chunk`` slice) falls back to contiguous, not the input stride.
|
| 99 |
"""
|
| 100 |
if contiguous:
|
| 101 |
return x.new_empty(x.shape)
|
| 102 |
return torch.empty_like(x)
|
| 103 |
|
| 104 |
|
| 105 |
+
@triton.autotune(configs=_activation_autotune_configs(), key=['D'], **autotune_cache_kwargs)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 106 |
@triton.jit(do_not_specialize=['T'])
|
| 107 |
+
def sigmoid_fwd_kernel(x, y, stride_x_row, stride_y_row, T, D: tl.constexpr, B: tl.constexpr):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 108 |
i_n = tl.program_id(0).to(tl.int64)
|
| 109 |
offs = i_n * B + tl.arange(0, B)
|
| 110 |
mask = offs < T
|
|
|
|
| 115 |
tl.store(y + row * stride_y_row + col, b_y.to(y.dtype.element_ty), mask=mask)
|
| 116 |
|
| 117 |
|
| 118 |
+
@triton.autotune(configs=_activation_autotune_configs(), key=['D'], **autotune_cache_kwargs)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 119 |
@triton.jit(do_not_specialize=['T'])
|
| 120 |
+
def sigmoid_bwd_kernel(x, dy, dx, stride_x_row, stride_dy_row, stride_dx_row, T, D: tl.constexpr, B: tl.constexpr):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 121 |
i_n = tl.program_id(0).to(tl.int64)
|
| 122 |
offs = i_n * B + tl.arange(0, B)
|
| 123 |
mask = offs < T
|
|
|
|
| 130 |
tl.store(dx + row * stride_dx_row + col, b_dx.to(dx.dtype.element_ty), mask=mask)
|
| 131 |
|
| 132 |
|
| 133 |
+
@dispatch
|
| 134 |
def sigmoid_fwd(x: torch.Tensor, output_contiguous: bool = False) -> torch.Tensor:
|
| 135 |
+
x = _ensure_inner_contiguous(x=x)
|
| 136 |
T, D = x.numel(), x.shape[-1]
|
| 137 |
+
y = _alloc_output(x=x, contiguous=output_contiguous)
|
| 138 |
sigmoid_fwd_kernel[lambda meta: (triton.cdiv(T, meta['B']),)](
|
| 139 |
x=x,
|
| 140 |
y=y,
|
| 141 |
+
stride_x_row=_get_stride(x=x),
|
| 142 |
+
stride_y_row=_get_stride(x=y),
|
| 143 |
T=T,
|
| 144 |
D=D,
|
| 145 |
)
|
| 146 |
return y
|
| 147 |
|
| 148 |
|
| 149 |
+
@dispatch
|
| 150 |
def sigmoid_bwd(x: torch.Tensor, dy: torch.Tensor, output_contiguous: bool = False) -> torch.Tensor:
|
| 151 |
+
x = _ensure_inner_contiguous(x=x)
|
| 152 |
+
dy = _ensure_inner_contiguous(x=dy)
|
| 153 |
T, D = x.numel(), x.shape[-1]
|
| 154 |
+
dx = _alloc_output(x=x, contiguous=output_contiguous)
|
| 155 |
sigmoid_bwd_kernel[lambda meta: (triton.cdiv(T, meta['B']),)](
|
| 156 |
x=x,
|
| 157 |
dy=dy,
|
| 158 |
dx=dx,
|
| 159 |
+
stride_x_row=_get_stride(x=x),
|
| 160 |
+
stride_dy_row=_get_stride(x=dy),
|
| 161 |
+
stride_dx_row=_get_stride(x=dx),
|
| 162 |
T=T,
|
| 163 |
D=D,
|
| 164 |
)
|
|
|
|
| 171 |
@input_guard(no_guard_contiguous=True)
|
| 172 |
def forward(ctx, x):
|
| 173 |
ctx.save_for_backward(x)
|
| 174 |
+
return sigmoid_fwd(x=x)
|
| 175 |
|
| 176 |
@staticmethod
|
| 177 |
@input_guard(no_guard_contiguous=True)
|
| 178 |
def backward(ctx, dout):
|
| 179 |
x, = ctx.saved_tensors
|
| 180 |
+
return sigmoid_bwd(x=x, dy=dout)
|
| 181 |
|
| 182 |
|
| 183 |
sigmoid = SigmoidFunction.apply
|
| 184 |
|
| 185 |
|
| 186 |
+
@triton.autotune(configs=_activation_autotune_configs(), key=['D'], **autotune_cache_kwargs)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 187 |
@triton.jit(do_not_specialize=['T'])
|
| 188 |
+
def elu_p1_fwd_kernel(x, y, stride_x_row, stride_y_row, T, D: tl.constexpr, B: tl.constexpr):
|
| 189 |
+
i_n = tl.program_id(0).to(tl.int64)
|
| 190 |
+
offs = i_n * B + tl.arange(0, B)
|
| 191 |
+
mask = offs < T
|
| 192 |
+
row = offs // D
|
| 193 |
+
col = offs % D
|
| 194 |
+
b_x = tl.load(x + row * stride_x_row + col, mask=mask, other=0.).to(tl.float32)
|
| 195 |
+
# libdevice preserves representable subnormal exponentials
|
| 196 |
+
b_y = tl.where(b_x >= 0, b_x + 1., libdevice.exp(tl.minimum(b_x, 0.)))
|
| 197 |
+
tl.store(y + row * stride_y_row + col, b_y.to(y.dtype.element_ty), mask=mask)
|
| 198 |
+
|
| 199 |
+
|
| 200 |
+
@triton.autotune(configs=_activation_autotune_configs(), key=['D'], **autotune_cache_kwargs)
|
| 201 |
+
@triton.jit(do_not_specialize=['T'])
|
| 202 |
+
def elu_p1_bwd_kernel(x, dy, dx, stride_x_row, stride_dy_row, stride_dx_row, T, D: tl.constexpr, B: tl.constexpr):
|
| 203 |
+
i_n = tl.program_id(0).to(tl.int64)
|
| 204 |
+
offs = i_n * B + tl.arange(0, B)
|
| 205 |
+
mask = offs < T
|
| 206 |
+
row = offs // D
|
| 207 |
+
col = offs % D
|
| 208 |
+
b_x = tl.load(x + row * stride_x_row + col, mask=mask, other=0.).to(tl.float32)
|
| 209 |
+
b_dy = tl.load(dy + row * stride_dy_row + col, mask=mask, other=0.).to(tl.float32)
|
| 210 |
+
b_dx = b_dy * libdevice.exp(tl.minimum(b_x, 0.))
|
| 211 |
+
tl.store(dx + row * stride_dx_row + col, b_dx.to(dx.dtype.element_ty), mask=mask)
|
| 212 |
+
|
| 213 |
+
|
| 214 |
+
@dispatch
|
| 215 |
+
def elu_p1_fwd(x: torch.Tensor) -> torch.Tensor:
|
| 216 |
+
x = x.contiguous() if x.ndim < 2 else _ensure_inner_contiguous(x=x)
|
| 217 |
+
T, D = x.numel(), x.shape[-1] if x.ndim else 1
|
| 218 |
+
y = _alloc_output(x=x)
|
| 219 |
+
if T > 0:
|
| 220 |
+
elu_p1_fwd_kernel[lambda meta: (triton.cdiv(T, meta['B']),)](
|
| 221 |
+
x=x,
|
| 222 |
+
y=y,
|
| 223 |
+
stride_x_row=_get_stride(x=x),
|
| 224 |
+
stride_y_row=_get_stride(x=y),
|
| 225 |
+
T=T,
|
| 226 |
+
D=D,
|
| 227 |
+
)
|
| 228 |
+
return y
|
| 229 |
+
|
| 230 |
+
|
| 231 |
+
@dispatch
|
| 232 |
+
def elu_p1_bwd(x: torch.Tensor, dy: torch.Tensor) -> torch.Tensor:
|
| 233 |
+
x = x.contiguous() if x.ndim < 2 else _ensure_inner_contiguous(x=x)
|
| 234 |
+
dy = dy.contiguous() if dy.ndim < 2 else _ensure_inner_contiguous(x=dy)
|
| 235 |
+
T, D = x.numel(), x.shape[-1] if x.ndim else 1
|
| 236 |
+
dx = _alloc_output(x=x)
|
| 237 |
+
if T > 0:
|
| 238 |
+
elu_p1_bwd_kernel[lambda meta: (triton.cdiv(T, meta['B']),)](
|
| 239 |
+
x=x,
|
| 240 |
+
dy=dy,
|
| 241 |
+
dx=dx,
|
| 242 |
+
stride_x_row=_get_stride(x=x),
|
| 243 |
+
stride_dy_row=_get_stride(x=dy),
|
| 244 |
+
stride_dx_row=_get_stride(x=dx),
|
| 245 |
+
T=T,
|
| 246 |
+
D=D,
|
| 247 |
+
)
|
| 248 |
+
return dx
|
| 249 |
+
|
| 250 |
+
|
| 251 |
+
class ELUPlusOneFunction(torch.autograd.Function):
|
| 252 |
+
|
| 253 |
+
@staticmethod
|
| 254 |
+
@input_guard(no_guard_contiguous=True)
|
| 255 |
+
@autocast_custom_fwd
|
| 256 |
+
def forward(ctx, x):
|
| 257 |
+
ctx.save_for_backward(x)
|
| 258 |
+
return elu_p1_fwd(x=x)
|
| 259 |
+
|
| 260 |
+
@staticmethod
|
| 261 |
+
@input_guard(no_guard_contiguous=True)
|
| 262 |
+
@autocast_custom_bwd
|
| 263 |
+
def backward(ctx, dout):
|
| 264 |
+
x, = ctx.saved_tensors
|
| 265 |
+
return elu_p1_bwd(x=x, dy=dout)
|
| 266 |
+
|
| 267 |
+
|
| 268 |
+
def elu_p1(x: torch.Tensor) -> torch.Tensor:
|
| 269 |
+
"""Compute ELU + 1 without cancellation in the negative branch."""
|
| 270 |
+
# triton-ascend 3.2.2 does not implement libdevice.exp
|
| 271 |
+
if IS_NPU or x.device.type == 'cpu' or x.dtype == torch.float64:
|
| 272 |
+
return torch.where(x >= 0, x + 1, x.clamp_max(0).exp()).to(x.dtype)
|
| 273 |
+
return ELUPlusOneFunction.apply(x)
|
| 274 |
+
|
| 275 |
+
|
| 276 |
+
@triton.autotune(configs=_activation_autotune_configs(), key=['D'], **autotune_cache_kwargs)
|
| 277 |
+
@triton.jit(do_not_specialize=['T'])
|
| 278 |
+
def logsigmoid_fwd_kernel(x, y, stride_x_row, stride_y_row, temperature, T, D: tl.constexpr, B: tl.constexpr):
|
| 279 |
i_n = tl.program_id(0).to(tl.int64)
|
| 280 |
offs = i_n * B + tl.arange(0, B)
|
| 281 |
mask = offs < T
|
|
|
|
| 288 |
tl.store(y + row * stride_y_row + col, b_y.to(y.dtype.element_ty), mask=mask)
|
| 289 |
|
| 290 |
|
| 291 |
+
@triton.autotune(configs=_activation_autotune_configs(), key=['D'], **autotune_cache_kwargs)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 292 |
@triton.jit(do_not_specialize=['T'])
|
| 293 |
def logsigmoid_bwd_kernel(
|
| 294 |
x,
|
|
|
|
| 313 |
tl.store(dx + row * stride_dx_row + col, b_dx.to(dx.dtype.element_ty), mask=mask)
|
| 314 |
|
| 315 |
|
| 316 |
+
@dispatch
|
| 317 |
def logsigmoid_fwd(x: torch.Tensor, temperature: float = 1., output_contiguous: bool = False) -> torch.Tensor:
|
| 318 |
+
x = _ensure_inner_contiguous(x=x)
|
| 319 |
T, D = x.numel(), x.shape[-1]
|
| 320 |
+
y = _alloc_output(x=x, contiguous=output_contiguous)
|
| 321 |
logsigmoid_fwd_kernel[lambda meta: (triton.cdiv(T, meta['B']),)](
|
| 322 |
x=x,
|
| 323 |
y=y,
|
| 324 |
+
stride_x_row=_get_stride(x=x),
|
| 325 |
+
stride_y_row=_get_stride(x=y),
|
| 326 |
temperature=temperature,
|
| 327 |
T=T,
|
| 328 |
D=D,
|
|
|
|
| 330 |
return y
|
| 331 |
|
| 332 |
|
| 333 |
+
@dispatch
|
| 334 |
def logsigmoid_bwd(
|
| 335 |
x: torch.Tensor,
|
| 336 |
dy: torch.Tensor,
|
| 337 |
temperature: float = 1.,
|
| 338 |
output_contiguous: bool = False,
|
| 339 |
) -> torch.Tensor:
|
| 340 |
+
x = _ensure_inner_contiguous(x=x)
|
| 341 |
+
dy = _ensure_inner_contiguous(x=dy)
|
| 342 |
T, D = x.numel(), x.shape[-1]
|
| 343 |
+
dx = _alloc_output(x=x, contiguous=output_contiguous)
|
| 344 |
logsigmoid_bwd_kernel[lambda meta: (triton.cdiv(T, meta['B']),)](
|
| 345 |
x=x,
|
| 346 |
dy=dy,
|
| 347 |
dx=dx,
|
| 348 |
+
stride_x_row=_get_stride(x=x),
|
| 349 |
+
stride_dy_row=_get_stride(x=dy),
|
| 350 |
+
stride_dx_row=_get_stride(x=dx),
|
| 351 |
temperature=temperature,
|
| 352 |
T=T,
|
| 353 |
D=D,
|
|
|
|
| 362 |
def forward(ctx, x, temperature):
|
| 363 |
ctx.save_for_backward(x)
|
| 364 |
ctx.temperature = temperature
|
| 365 |
+
return logsigmoid_fwd(x=x, temperature=temperature)
|
| 366 |
|
| 367 |
@staticmethod
|
| 368 |
@input_guard(no_guard_contiguous=True)
|
| 369 |
def backward(ctx, dy):
|
| 370 |
x, = ctx.saved_tensors
|
| 371 |
+
return logsigmoid_bwd(x=x, dy=dy, temperature=ctx.temperature), None
|
| 372 |
|
| 373 |
|
| 374 |
def logsigmoid(x: torch.Tensor, temperature: float = 1.) -> torch.Tensor:
|
| 375 |
return LogSigmoidFunction.apply(x, temperature)
|
| 376 |
|
| 377 |
|
| 378 |
+
@triton.autotune(configs=_activation_autotune_configs(), key=['D'], **autotune_cache_kwargs)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 379 |
@triton.jit(do_not_specialize=['T'])
|
| 380 |
+
def swish_fwd_kernel(x, y, stride_x_row, stride_y_row, T, D: tl.constexpr, B: tl.constexpr):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 381 |
i_n = tl.program_id(0).to(tl.int64)
|
| 382 |
offs = i_n * B + tl.arange(0, B)
|
| 383 |
mask = offs < T
|
|
|
|
| 388 |
tl.store(y + row * stride_y_row + col, b_y.to(y.dtype.element_ty), mask=mask)
|
| 389 |
|
| 390 |
|
| 391 |
+
@triton.autotune(configs=_activation_autotune_configs(), key=['D'], **autotune_cache_kwargs)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 392 |
@triton.jit(do_not_specialize=['T'])
|
| 393 |
+
def swish_bwd_kernel(x, dy, dx, stride_x_row, stride_dy_row, stride_dx_row, T, D: tl.constexpr, B: tl.constexpr):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 394 |
i_n = tl.program_id(0).to(tl.int64)
|
| 395 |
offs = i_n * B + tl.arange(0, B)
|
| 396 |
mask = offs < T
|
|
|
|
| 403 |
tl.store(dx + row * stride_dx_row + col, b_dx.to(dx.dtype.element_ty), mask=mask)
|
| 404 |
|
| 405 |
|
| 406 |
+
@dispatch
|
| 407 |
def swish_fwd(x: torch.Tensor, output_contiguous: bool = False) -> torch.Tensor:
|
| 408 |
+
x = _ensure_inner_contiguous(x=x)
|
| 409 |
T, D = x.numel(), x.shape[-1]
|
| 410 |
+
y = _alloc_output(x=x, contiguous=output_contiguous)
|
| 411 |
swish_fwd_kernel[lambda meta: (triton.cdiv(T, meta['B']),)](
|
| 412 |
x=x,
|
| 413 |
y=y,
|
| 414 |
+
stride_x_row=_get_stride(x=x),
|
| 415 |
+
stride_y_row=_get_stride(x=y),
|
| 416 |
T=T,
|
| 417 |
D=D,
|
| 418 |
)
|
| 419 |
return y
|
| 420 |
|
| 421 |
|
| 422 |
+
@dispatch
|
| 423 |
def swish_bwd(x: torch.Tensor, dy: torch.Tensor, output_contiguous: bool = False) -> torch.Tensor:
|
| 424 |
+
x = _ensure_inner_contiguous(x=x)
|
| 425 |
+
dy = _ensure_inner_contiguous(x=dy)
|
| 426 |
T, D = x.numel(), x.shape[-1]
|
| 427 |
+
dx = _alloc_output(x=x, contiguous=output_contiguous)
|
| 428 |
swish_bwd_kernel[lambda meta: (triton.cdiv(T, meta['B']),)](
|
| 429 |
x=x,
|
| 430 |
dy=dy,
|
| 431 |
dx=dx,
|
| 432 |
+
stride_x_row=_get_stride(x=x),
|
| 433 |
+
stride_dy_row=_get_stride(x=dy),
|
| 434 |
+
stride_dx_row=_get_stride(x=dx),
|
| 435 |
T=T,
|
| 436 |
D=D,
|
| 437 |
)
|
|
|
|
| 444 |
@input_guard(no_guard_contiguous=True)
|
| 445 |
def forward(ctx, x):
|
| 446 |
ctx.save_for_backward(x)
|
| 447 |
+
return swish_fwd(x=x)
|
| 448 |
|
| 449 |
@staticmethod
|
| 450 |
@input_guard(no_guard_contiguous=True)
|
| 451 |
def backward(ctx, dout):
|
| 452 |
x, = ctx.saved_tensors
|
| 453 |
+
return swish_bwd(x=x, dy=dout)
|
| 454 |
|
| 455 |
|
| 456 |
swish = SwishFunction.apply
|
|
|
|
| 460 |
# sqrt(2/pi) -> 0.79788456
|
| 461 |
|
| 462 |
|
| 463 |
+
# use the tanh GELU approximation.
|
|
|
|
|
|
|
| 464 |
@torch.compile
|
| 465 |
def bias_gelu(y, bias):
|
| 466 |
x = bias + y
|
| 467 |
return (x * 0.5 * (1.0 + torch.tanh(0.79788456 * x * (1 + 0.044715 * x * x)))).to(dtype=y.dtype)
|
| 468 |
|
| 469 |
|
|
|
|
|
|
|
|
|
|
| 470 |
@torch.compile
|
| 471 |
def bias_gelu_bwd(g, y, bias):
|
| 472 |
+
"""Inputs have shape [B, D] and bias has shape [D]."""
|
| 473 |
x = bias + y
|
| 474 |
tanh_out = torch.tanh(0.79788456 * x * (1 + 0.044715 * x * x))
|
| 475 |
# sqrt(2/pi) * 3 * 0.044715 -> 0.1070322243
|
| 476 |
+
ff = 0.5 * x * ((1 - tanh_out * tanh_out) * (0.79788456 + 0.1070322243 * x * x)) + 0.5 * (1 + tanh_out)
|
|
|
|
|
|
|
| 477 |
grad_y = ff * g
|
| 478 |
return grad_y.to(dtype=y.dtype), grad_y.sum(dim=(0), dtype=bias.dtype)
|
| 479 |
|
|
|
|
| 481 |
class GeLUFunction(torch.autograd.Function):
|
| 482 |
|
| 483 |
@staticmethod
|
|
|
|
| 484 |
def forward(ctx, input, bias):
|
| 485 |
ctx.save_for_backward(input, bias)
|
| 486 |
+
return bias_gelu(y=input, bias=bias)
|
| 487 |
|
| 488 |
@staticmethod
|
| 489 |
def backward(ctx, grad_output):
|
| 490 |
input, bias = ctx.saved_tensors
|
| 491 |
+
return bias_gelu_bwd(g=grad_output, y=input, bias=bias)
|
| 492 |
|
| 493 |
|
| 494 |
bias_gelu_impl = GeLUFunction.apply
|
| 495 |
|
| 496 |
|
| 497 |
+
# use the tanh GELU approximation.
|
|
|
|
|
|
|
|
|
|
| 498 |
@torch.compile
|
| 499 |
def gelu_fwd(x):
|
| 500 |
return (x * 0.5 * (1.0 + torch.tanh(0.79788456 * x * (1 + 0.044715 * x * x)))).to(dtype=x.dtype)
|
| 501 |
|
| 502 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 503 |
@torch.compile
|
| 504 |
def gelu_bwd(g, x):
|
| 505 |
tanh_out = torch.tanh(0.79788456 * x * (1 + 0.044715 * x * x))
|
| 506 |
# sqrt(2/pi) * 3 * 0.044715 -> 0.1070322243
|
| 507 |
+
ff = 0.5 * x * ((1 - tanh_out * tanh_out) * (0.79788456 + 0.1070322243 * x * x)) + 0.5 * (1 + tanh_out)
|
|
|
|
|
|
|
| 508 |
return (ff * g).to(dtype=x.dtype)
|
| 509 |
|
| 510 |
|
| 511 |
class FastGeLUFunction(torch.autograd.Function):
|
| 512 |
@staticmethod
|
|
|
|
| 513 |
def forward(ctx, input):
|
| 514 |
ctx.save_for_backward(input)
|
| 515 |
+
return gelu_fwd(x=input)
|
| 516 |
|
| 517 |
@staticmethod
|
| 518 |
def backward(ctx, grad_output):
|
| 519 |
(input,) = ctx.saved_tensors
|
| 520 |
+
tmp = gelu_bwd(g=grad_output, x=input)
|
| 521 |
return tmp
|
| 522 |
|
| 523 |
|
|
|
|
| 529 |
return torch.where(x >= 0, g, 0.0).to(dtype=x.dtype)
|
| 530 |
|
| 531 |
|
|
|
|
| 532 |
@torch.compile
|
| 533 |
def sqrelu_fwd(x):
|
| 534 |
r = F.relu(x.float())
|
| 535 |
return (r * r).to(dtype=x.dtype)
|
| 536 |
|
| 537 |
|
|
|
|
| 538 |
@torch.compile
|
| 539 |
def sqrelu_bwd(g, x):
|
| 540 |
return (2.0 * g * F.relu(x.float())).to(dtype=x.dtype)
|
|
|
|
| 545 |
@staticmethod
|
| 546 |
def forward(ctx, input):
|
| 547 |
ctx.save_for_backward(input)
|
| 548 |
+
return sqrelu_fwd(x=input)
|
| 549 |
|
| 550 |
@staticmethod
|
| 551 |
def backward(ctx, grad_output):
|
| 552 |
input, = ctx.saved_tensors
|
| 553 |
+
return sqrelu_bwd(g=grad_output, x=input)
|
| 554 |
|
| 555 |
|
| 556 |
sqrelu = SquaredReLUFunction.apply
|
| 557 |
|
| 558 |
|
| 559 |
+
@triton.autotune(configs=_activation_autotune_configs(), key=['D'], **autotune_cache_kwargs)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 560 |
@triton.jit(do_not_specialize=['T'])
|
| 561 |
+
def swiglu_fwd_kernel(x, y, z, stride_x_row, stride_y_row, stride_z_row, T, D: tl.constexpr, B: tl.constexpr):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 562 |
i_n = tl.program_id(0).to(tl.int64)
|
| 563 |
offs = i_n * B + tl.arange(0, B)
|
| 564 |
mask = offs < T
|
|
|
|
| 570 |
tl.store(z + row * stride_z_row + col, b_z.to(z.dtype.element_ty), mask=mask)
|
| 571 |
|
| 572 |
|
| 573 |
+
@triton.heuristics({'HAS_WEIGHT': lambda args: args['z'] is not None})
|
| 574 |
+
@triton.autotune(configs=_activation_autotune_configs(), key=['D'], **autotune_cache_kwargs)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 575 |
@triton.jit(do_not_specialize=['T'])
|
| 576 |
def swiglu_fwdbwd_kernel(
|
| 577 |
+
x,
|
| 578 |
+
y,
|
| 579 |
+
g,
|
| 580 |
+
dx,
|
| 581 |
+
dy,
|
| 582 |
+
z,
|
| 583 |
stride_x_row,
|
| 584 |
stride_y_row,
|
| 585 |
stride_g_row,
|
|
|
|
| 612 |
tl.store(z + row * stride_z_row + col, b_z.to(z.dtype.element_ty), mask=mask)
|
| 613 |
|
| 614 |
|
| 615 |
+
@dispatch
|
| 616 |
def swiglu_fwd(x: torch.Tensor, y: torch.Tensor, output_contiguous: bool = False) -> torch.Tensor:
|
| 617 |
assert x.shape == y.shape, f"swiglu_fwd: shape mismatch x={x.shape} y={y.shape}"
|
| 618 |
+
x = _ensure_inner_contiguous(x=x)
|
| 619 |
+
y = _ensure_inner_contiguous(x=y)
|
| 620 |
T, D = x.numel(), x.shape[-1]
|
| 621 |
+
z = _alloc_output(x=x, contiguous=output_contiguous)
|
| 622 |
swiglu_fwd_kernel[lambda meta: (triton.cdiv(T, meta['B']),)](
|
| 623 |
x=x,
|
| 624 |
y=y,
|
| 625 |
z=z,
|
| 626 |
+
stride_x_row=_get_stride(x=x),
|
| 627 |
+
stride_y_row=_get_stride(x=y),
|
| 628 |
+
stride_z_row=_get_stride(x=z),
|
| 629 |
T=T,
|
| 630 |
D=D,
|
| 631 |
)
|
| 632 |
return z
|
| 633 |
|
| 634 |
|
| 635 |
+
@dispatch
|
| 636 |
def swiglu_fwdbwd(
|
| 637 |
x: torch.Tensor,
|
| 638 |
y: torch.Tensor,
|
|
|
|
| 641 |
output_contiguous: bool = False,
|
| 642 |
):
|
| 643 |
assert x.shape == y.shape == g.shape, f"swiglu_fwdbwd: shape mismatch x={x.shape} y={y.shape} g={g.shape}"
|
| 644 |
+
x = _ensure_inner_contiguous(x=x)
|
| 645 |
+
y = _ensure_inner_contiguous(x=y)
|
| 646 |
+
g = _ensure_inner_contiguous(x=g)
|
| 647 |
T, D = x.numel(), x.shape[-1]
|
| 648 |
+
dx = _alloc_output(x=x, contiguous=output_contiguous)
|
| 649 |
+
dy = _alloc_output(x=y, contiguous=output_contiguous)
|
| 650 |
if use_weight:
|
| 651 |
+
z = _alloc_output(x=x, contiguous=output_contiguous)
|
| 652 |
else:
|
| 653 |
z = None
|
| 654 |
swiglu_fwdbwd_kernel[lambda meta: (triton.cdiv(T, meta['B']),)](
|
|
|
|
| 658 |
dx=dx,
|
| 659 |
dy=dy,
|
| 660 |
z=z,
|
| 661 |
+
stride_x_row=_get_stride(x=x),
|
| 662 |
+
stride_y_row=_get_stride(x=y),
|
| 663 |
+
stride_g_row=_get_stride(x=g),
|
| 664 |
+
stride_dx_row=_get_stride(x=dx),
|
| 665 |
+
stride_dy_row=_get_stride(x=dy),
|
| 666 |
+
stride_z_row=_get_stride(x=z) if z is not None else 0,
|
| 667 |
T=T,
|
| 668 |
D=D,
|
| 669 |
)
|
|
|
|
| 684 |
@input_guard(no_guard_contiguous=True)
|
| 685 |
def forward(ctx, x, y):
|
| 686 |
ctx.save_for_backward(x, y)
|
| 687 |
+
return swiglu_fwd(x=x, y=y)
|
| 688 |
|
| 689 |
@staticmethod
|
| 690 |
@input_guard(no_guard_contiguous=True)
|
| 691 |
def backward(ctx, dout):
|
| 692 |
x, y = ctx.saved_tensors
|
| 693 |
+
return swiglu_fwdbwd(x=x, y=y, g=dout)
|
| 694 |
|
| 695 |
|
| 696 |
class SwiGLULinearFunction(torch.autograd.Function):
|
|
|
|
| 707 |
@input_guard(no_guard_contiguous=True)
|
| 708 |
@autocast_custom_fwd
|
| 709 |
def forward(ctx, x, y, weight, bias):
|
| 710 |
+
z = swiglu_fwd(x=x, y=y, output_contiguous=True)
|
| 711 |
out = F.linear(z, weight, bias)
|
| 712 |
ctx.save_for_backward(x, y, weight)
|
|
|
|
| 713 |
return out
|
| 714 |
|
| 715 |
@staticmethod
|
|
|
|
| 718 |
def backward(ctx, dout, *args):
|
| 719 |
x, y, weight = ctx.saved_tensors
|
| 720 |
dout = dout.reshape(-1, dout.shape[-1])
|
| 721 |
+
dx = dy = dlinear_weight = None
|
| 722 |
+
if ctx.needs_input_grad[0] or ctx.needs_input_grad[1]:
|
| 723 |
+
dz = F.linear(dout, weight.t()).view_as(x)
|
| 724 |
+
if ctx.needs_input_grad[2]:
|
| 725 |
+
dx, dy, z = swiglu_fwdbwd(x=x, y=y, g=dz, use_weight=True, output_contiguous=True)
|
| 726 |
+
else:
|
| 727 |
+
dx, dy = swiglu_fwdbwd(x=x, y=y, g=dz, output_contiguous=True)
|
| 728 |
+
elif ctx.needs_input_grad[2]:
|
| 729 |
+
z = swiglu_fwd(x=x, y=y, output_contiguous=True)
|
| 730 |
+
if ctx.needs_input_grad[2]:
|
| 731 |
+
dlinear_weight = torch.einsum("bo,bi->oi", dout, z.reshape(-1, z.shape[-1]))
|
| 732 |
+
dlinear_bias = dout.sum(0) if ctx.needs_input_grad[3] else None
|
| 733 |
return dx, dy, dlinear_weight, dlinear_bias
|
| 734 |
|
| 735 |
|
| 736 |
swiglu = SwiGLUFunction.apply
|
| 737 |
|
| 738 |
|
| 739 |
+
@dispatch
|
| 740 |
def swiglu_linear(x, y, weight, bias):
|
| 741 |
return SwiGLULinearFunction.apply(x, y, weight, bias)
|
| 742 |
|
| 743 |
|
| 744 |
+
@triton.autotune(configs=_activation_autotune_configs(), key=['D'], **autotune_cache_kwargs)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 745 |
@triton.jit(do_not_specialize=['T'])
|
| 746 |
+
def sigmoidglu_fwd_kernel(x, y, z, stride_x_row, stride_y_row, stride_z_row, T, D: tl.constexpr, B: tl.constexpr):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 747 |
i_n = tl.program_id(0).to(tl.int64)
|
| 748 |
offs = i_n * B + tl.arange(0, B)
|
| 749 |
mask = offs < T
|
|
|
|
| 755 |
tl.store(z + row * stride_z_row + col, b_z.to(z.dtype.element_ty), mask=mask)
|
| 756 |
|
| 757 |
|
| 758 |
+
@triton.heuristics({'HAS_WEIGHT': lambda args: args['z'] is not None})
|
| 759 |
+
@triton.autotune(configs=_activation_autotune_configs(), key=['D'], **autotune_cache_kwargs)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 760 |
@triton.jit(do_not_specialize=['T'])
|
| 761 |
def sigmoidglu_fwdbwd_kernel(
|
| 762 |
+
x,
|
| 763 |
+
y,
|
| 764 |
+
g,
|
| 765 |
+
dx,
|
| 766 |
+
dy,
|
| 767 |
+
z,
|
| 768 |
stride_x_row,
|
| 769 |
stride_y_row,
|
| 770 |
stride_g_row,
|
|
|
|
| 799 |
@torch.compiler.disable
|
| 800 |
def sigmoidglu_fwd(x: torch.Tensor, y: torch.Tensor, output_contiguous: bool = False) -> torch.Tensor:
|
| 801 |
assert x.shape == y.shape, f"sigmoidglu_fwd: shape mismatch x={x.shape} y={y.shape}"
|
| 802 |
+
x = _ensure_inner_contiguous(x=x)
|
| 803 |
+
y = _ensure_inner_contiguous(x=y)
|
| 804 |
T, D = x.numel(), x.shape[-1]
|
| 805 |
+
z = _alloc_output(x=x, contiguous=output_contiguous)
|
| 806 |
sigmoidglu_fwd_kernel[lambda meta: (triton.cdiv(T, meta['B']),)](
|
| 807 |
x=x,
|
| 808 |
y=y,
|
| 809 |
z=z,
|
| 810 |
+
stride_x_row=_get_stride(x=x),
|
| 811 |
+
stride_y_row=_get_stride(x=y),
|
| 812 |
+
stride_z_row=_get_stride(x=z),
|
| 813 |
T=T,
|
| 814 |
D=D,
|
| 815 |
)
|
|
|
|
| 825 |
output_contiguous: bool = False,
|
| 826 |
):
|
| 827 |
assert x.shape == y.shape == g.shape, f"sigmoidglu_fwdbwd: shape mismatch x={x.shape} y={y.shape} g={g.shape}"
|
| 828 |
+
x = _ensure_inner_contiguous(x=x)
|
| 829 |
+
y = _ensure_inner_contiguous(x=y)
|
| 830 |
+
g = _ensure_inner_contiguous(x=g)
|
| 831 |
T, D = x.numel(), x.shape[-1]
|
| 832 |
+
dx = _alloc_output(x=x, contiguous=output_contiguous)
|
| 833 |
+
dy = _alloc_output(x=y, contiguous=output_contiguous)
|
| 834 |
if use_weight:
|
| 835 |
+
z = _alloc_output(x=x, contiguous=output_contiguous)
|
| 836 |
else:
|
| 837 |
z = None
|
| 838 |
sigmoidglu_fwdbwd_kernel[lambda meta: (triton.cdiv(T, meta['B']),)](
|
|
|
|
| 842 |
dx=dx,
|
| 843 |
dy=dy,
|
| 844 |
z=z,
|
| 845 |
+
stride_x_row=_get_stride(x=x),
|
| 846 |
+
stride_y_row=_get_stride(x=y),
|
| 847 |
+
stride_g_row=_get_stride(x=g),
|
| 848 |
+
stride_dx_row=_get_stride(x=dx),
|
| 849 |
+
stride_dy_row=_get_stride(x=dy),
|
| 850 |
+
stride_z_row=_get_stride(x=z) if z is not None else 0,
|
| 851 |
T=T,
|
| 852 |
D=D,
|
| 853 |
)
|
|
|
|
| 868 |
@input_guard(no_guard_contiguous=True)
|
| 869 |
def forward(ctx, x, y):
|
| 870 |
ctx.save_for_backward(x, y)
|
| 871 |
+
return sigmoidglu_fwd(x=x, y=y)
|
| 872 |
|
| 873 |
@staticmethod
|
| 874 |
@input_guard(no_guard_contiguous=True)
|
| 875 |
def backward(ctx, dout):
|
| 876 |
x, y = ctx.saved_tensors
|
| 877 |
+
return sigmoidglu_fwdbwd(x=x, y=y, g=dout)
|
| 878 |
|
| 879 |
|
| 880 |
class SigmoidGLULinearFunction(torch.autograd.Function):
|
|
|
|
| 891 |
@input_guard(no_guard_contiguous=True)
|
| 892 |
@autocast_custom_fwd
|
| 893 |
def forward(ctx, x, y, weight, bias):
|
| 894 |
+
z = sigmoidglu_fwd(x=x, y=y, output_contiguous=True)
|
| 895 |
out = F.linear(z, weight, bias)
|
| 896 |
ctx.save_for_backward(x, y, weight)
|
| 897 |
ctx.linear_bias_is_none = bias is None
|
|
|
|
| 904 |
x, y, weight = ctx.saved_tensors
|
| 905 |
dout = dout.reshape(-1, dout.shape[-1])
|
| 906 |
dz = F.linear(dout, weight.t()).view_as(x)
|
| 907 |
+
dx, dy, z = sigmoidglu_fwdbwd(x=x, y=y, g=dz, use_weight=True, output_contiguous=True)
|
| 908 |
dlinear_weight = torch.einsum("bo,bi->oi", dout, z.reshape(-1, z.shape[-1]))
|
| 909 |
dlinear_bias = None if ctx.linear_bias_is_none else dout.sum(0)
|
| 910 |
return dx, dy, dlinear_weight, dlinear_bias
|
|
|
|
| 916 |
sigmoidglu_linear = SigmoidGLULinearFunction.apply
|
| 917 |
|
| 918 |
|
| 919 |
+
@triton.autotune(configs=_activation_autotune_configs(), key=['D'], **autotune_cache_kwargs)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 920 |
@triton.jit(do_not_specialize=['T'])
|
| 921 |
+
def powglu_fwd_kernel(x, y, z, stride_x_row, stride_y_row, stride_z_row, m, T, D: tl.constexpr, B: tl.constexpr):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 922 |
i_n = tl.program_id(0).to(tl.int64)
|
| 923 |
offs = i_n * B + tl.arange(0, B)
|
| 924 |
mask = offs < T
|
|
|
|
| 938 |
tl.store(z + row * stride_z_row + col, b_z.to(z.dtype.element_ty), mask=mask)
|
| 939 |
|
| 940 |
|
| 941 |
+
@triton.heuristics({'HAS_WEIGHT': lambda args: args['z'] is not None})
|
| 942 |
+
@triton.autotune(configs=_activation_autotune_configs(), key=['D'], **autotune_cache_kwargs)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 943 |
@triton.jit(do_not_specialize=['T'])
|
| 944 |
def powglu_fwdbwd_kernel(
|
| 945 |
+
x,
|
| 946 |
+
y,
|
| 947 |
+
g,
|
| 948 |
+
dx,
|
| 949 |
+
dy,
|
| 950 |
+
z,
|
| 951 |
stride_x_row,
|
| 952 |
stride_y_row,
|
| 953 |
stride_g_row,
|
|
|
|
| 997 |
tl.store(z + row * stride_z_row + col, b_z.to(z.dtype.element_ty), mask=mask)
|
| 998 |
|
| 999 |
|
| 1000 |
+
@dispatch
|
| 1001 |
def powglu_fwd(x: torch.Tensor, y: torch.Tensor, power: float = 3.0, output_contiguous: bool = False) -> torch.Tensor:
|
| 1002 |
assert x.shape == y.shape, f"powglu_fwd: shape mismatch x={x.shape} y={y.shape}"
|
| 1003 |
+
x = _ensure_inner_contiguous(x=x)
|
| 1004 |
+
y = _ensure_inner_contiguous(x=y)
|
| 1005 |
T, D = x.numel(), x.shape[-1]
|
| 1006 |
+
z = _alloc_output(x=x, contiguous=output_contiguous)
|
| 1007 |
powglu_fwd_kernel[lambda meta: (triton.cdiv(T, meta['B']),)](
|
| 1008 |
x=x,
|
| 1009 |
y=y,
|
| 1010 |
z=z,
|
| 1011 |
+
stride_x_row=_get_stride(x=x),
|
| 1012 |
+
stride_y_row=_get_stride(x=y),
|
| 1013 |
+
stride_z_row=_get_stride(x=z),
|
| 1014 |
m=power,
|
| 1015 |
T=T,
|
| 1016 |
D=D,
|
|
|
|
| 1018 |
return z
|
| 1019 |
|
| 1020 |
|
| 1021 |
+
@dispatch
|
| 1022 |
def powglu_fwdbwd(
|
| 1023 |
x: torch.Tensor,
|
| 1024 |
y: torch.Tensor,
|
|
|
|
| 1028 |
output_contiguous: bool = False,
|
| 1029 |
):
|
| 1030 |
assert x.shape == y.shape == g.shape, f"powglu_fwdbwd: shape mismatch x={x.shape} y={y.shape} g={g.shape}"
|
| 1031 |
+
x = _ensure_inner_contiguous(x=x)
|
| 1032 |
+
y = _ensure_inner_contiguous(x=y)
|
| 1033 |
+
g = _ensure_inner_contiguous(x=g)
|
| 1034 |
T, D = x.numel(), x.shape[-1]
|
| 1035 |
+
dx = _alloc_output(x=x, contiguous=output_contiguous)
|
| 1036 |
+
dy = _alloc_output(x=y, contiguous=output_contiguous)
|
| 1037 |
if use_weight:
|
| 1038 |
+
z = _alloc_output(x=x, contiguous=output_contiguous)
|
| 1039 |
else:
|
| 1040 |
z = None
|
| 1041 |
powglu_fwdbwd_kernel[lambda meta: (triton.cdiv(T, meta['B']),)](
|
|
|
|
| 1045 |
dx=dx,
|
| 1046 |
dy=dy,
|
| 1047 |
z=z,
|
| 1048 |
+
stride_x_row=_get_stride(x=x),
|
| 1049 |
+
stride_y_row=_get_stride(x=y),
|
| 1050 |
+
stride_g_row=_get_stride(x=g),
|
| 1051 |
+
stride_dx_row=_get_stride(x=dx),
|
| 1052 |
+
stride_dy_row=_get_stride(x=dy),
|
| 1053 |
+
stride_z_row=_get_stride(x=z) if z is not None else 0,
|
| 1054 |
m=power,
|
| 1055 |
T=T,
|
| 1056 |
D=D,
|
|
|
|
| 1068 |
\text{PowGLU}(x, y) = g(x) * y,\quad
|
| 1069 |
g(x) = \begin{cases} x^{power/(\sqrt{x}+1)}\,\sigma(x) & x > 0 \\ x\,\sigma(x) & x \le 0 \end{cases}
|
| 1070 |
|
| 1071 |
+
For ``x <= 0`` the gate reduces to swish, matching SwiGLU; for large ``x > 0`` it saturates instead of growing,
|
| 1072 |
+
replacing SwiGLU's quadratic amplification with bounded growth (Power Linear Unit, arXiv:2605.25704).
|
| 1073 |
"""
|
| 1074 |
|
| 1075 |
@staticmethod
|
|
|
|
| 1077 |
def forward(ctx, x, y, power):
|
| 1078 |
ctx.save_for_backward(x, y)
|
| 1079 |
ctx.power = power
|
| 1080 |
+
return powglu_fwd(x=x, y=y, power=power)
|
| 1081 |
|
| 1082 |
@staticmethod
|
| 1083 |
@input_guard(no_guard_contiguous=True)
|
| 1084 |
def backward(ctx, dout):
|
| 1085 |
x, y = ctx.saved_tensors
|
| 1086 |
+
dx, dy = powglu_fwdbwd(x=x, y=y, g=dout, power=ctx.power)
|
| 1087 |
return dx, dy, None
|
| 1088 |
|
| 1089 |
|
|
|
|
| 1101 |
@input_guard(no_guard_contiguous=True)
|
| 1102 |
@autocast_custom_fwd
|
| 1103 |
def forward(ctx, x, y, weight, bias, power):
|
| 1104 |
+
z = powglu_fwd(x=x, y=y, power=power, output_contiguous=True)
|
| 1105 |
out = F.linear(z, weight, bias)
|
| 1106 |
ctx.save_for_backward(x, y, weight)
|
| 1107 |
ctx.linear_bias_is_none = bias is None
|
|
|
|
| 1115 |
x, y, weight = ctx.saved_tensors
|
| 1116 |
dout = dout.reshape(-1, dout.shape[-1])
|
| 1117 |
dz = F.linear(dout, weight.t()).view_as(x)
|
| 1118 |
+
dx, dy, z = powglu_fwdbwd(x=x, y=y, g=dz, power=ctx.power, use_weight=True, output_contiguous=True)
|
| 1119 |
dlinear_weight = torch.einsum("bo,bi->oi", dout, z.reshape(-1, z.shape[-1]))
|
| 1120 |
dlinear_bias = None if ctx.linear_bias_is_none else dout.sum(0)
|
| 1121 |
return dx, dy, dlinear_weight, dlinear_bias, None
|
|
|
|
| 1125 |
return PowGLUFunction.apply(x, y, power)
|
| 1126 |
|
| 1127 |
|
| 1128 |
+
@dispatch
|
| 1129 |
def powglu_linear(
|
| 1130 |
x: torch.Tensor,
|
| 1131 |
y: torch.Tensor,
|
build/torch-cuda/modules/backends/__init__.py
DELETED
|
@@ -1,17 +0,0 @@
|
|
| 1 |
-
# Copyright (c) 2023-2026, Songlin Yang, Yu Zhang, Zhiyuan Li
|
| 2 |
-
#
|
| 3 |
-
# This source code is licensed under the MIT license found in the
|
| 4 |
-
# LICENSE file in the root directory of this source tree.
|
| 5 |
-
# For a list of all contributors, visit:
|
| 6 |
-
# https://github.com/fla-org/flash-linear-attention/graphs/contributors
|
| 7 |
-
|
| 8 |
-
"""Module-level backends for FLA components such as rotary and cross-entropy."""
|
| 9 |
-
|
| 10 |
-
from ...modules.backends.triton_ascend import TritonAscendBackend
|
| 11 |
-
from ...ops.backends import BackendRegistry, dispatch
|
| 12 |
-
|
| 13 |
-
modules_registry = BackendRegistry("modules")
|
| 14 |
-
|
| 15 |
-
modules_registry.register(TritonAscendBackend())
|
| 16 |
-
|
| 17 |
-
__all__ = ['dispatch', 'modules_registry']
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
build/torch-cuda/modules/backends/triton_ascend/__init__.py
DELETED
|
@@ -1,422 +0,0 @@
|
|
| 1 |
-
# Copyright (c) 2023-2026, Songlin Yang, Yu Zhang, Zhiyuan Li
|
| 2 |
-
#
|
| 3 |
-
# This source code is licensed under the MIT license found in the
|
| 4 |
-
# LICENSE file in the root directory of this source tree.
|
| 5 |
-
# For a list of all contributors, visit:
|
| 6 |
-
# https://github.com/fla-org/flash-linear-attention/graphs/contributors
|
| 7 |
-
|
| 8 |
-
"""Triton-Ascend (Huawei NPU) backend for FLA modules."""
|
| 9 |
-
|
| 10 |
-
from __future__ import annotations
|
| 11 |
-
|
| 12 |
-
from ....ops.backends import BaseBackend
|
| 13 |
-
|
| 14 |
-
|
| 15 |
-
class TritonAscendBackend(BaseBackend):
|
| 16 |
-
"""Ascend NPU backend using triton-ascend kernels."""
|
| 17 |
-
|
| 18 |
-
backend_type = "triton_ascend"
|
| 19 |
-
package_name = None
|
| 20 |
-
env_var = None
|
| 21 |
-
priority = 0
|
| 22 |
-
|
| 23 |
-
@classmethod
|
| 24 |
-
def is_available(cls) -> bool:
|
| 25 |
-
from ....utils import IS_NPU
|
| 26 |
-
return IS_NPU
|
| 27 |
-
|
| 28 |
-
def rotary_embedding_fwdbwd(
|
| 29 |
-
self,
|
| 30 |
-
x,
|
| 31 |
-
cos,
|
| 32 |
-
sin,
|
| 33 |
-
seqlen_offsets=0,
|
| 34 |
-
cu_seqlens=None,
|
| 35 |
-
interleaved=False,
|
| 36 |
-
inplace=False,
|
| 37 |
-
conjugate=False,
|
| 38 |
-
chunk_indices=None,
|
| 39 |
-
):
|
| 40 |
-
from ....modules.backends.triton_ascend.rotary import rotary_embedding_fwdbwd_npu
|
| 41 |
-
return rotary_embedding_fwdbwd_npu(
|
| 42 |
-
x,
|
| 43 |
-
cos,
|
| 44 |
-
sin,
|
| 45 |
-
seqlen_offsets=seqlen_offsets,
|
| 46 |
-
cu_seqlens=cu_seqlens,
|
| 47 |
-
interleaved=interleaved,
|
| 48 |
-
inplace=inplace,
|
| 49 |
-
conjugate=conjugate,
|
| 50 |
-
chunk_indices=chunk_indices,
|
| 51 |
-
)
|
| 52 |
-
|
| 53 |
-
def cross_entropy_loss(
|
| 54 |
-
self,
|
| 55 |
-
logits,
|
| 56 |
-
target,
|
| 57 |
-
label_smoothing=0.0,
|
| 58 |
-
logit_scale=1.0,
|
| 59 |
-
lse_square_scale=0.0,
|
| 60 |
-
logit_softcapping=None,
|
| 61 |
-
ignore_index=-100,
|
| 62 |
-
inplace_backward=False,
|
| 63 |
-
process_group=None,
|
| 64 |
-
):
|
| 65 |
-
from ....modules.backends.triton_ascend.fused_cross_entropy import (
|
| 66 |
-
cross_entropy_loss_npu,
|
| 67 |
-
)
|
| 68 |
-
return cross_entropy_loss_npu(
|
| 69 |
-
logits,
|
| 70 |
-
target,
|
| 71 |
-
label_smoothing,
|
| 72 |
-
logit_scale,
|
| 73 |
-
lse_square_scale,
|
| 74 |
-
logit_softcapping,
|
| 75 |
-
ignore_index,
|
| 76 |
-
inplace_backward,
|
| 77 |
-
process_group,
|
| 78 |
-
)
|
| 79 |
-
|
| 80 |
-
def logsumexp_fwd(
|
| 81 |
-
self,
|
| 82 |
-
x,
|
| 83 |
-
scale=None,
|
| 84 |
-
softcapping=None,
|
| 85 |
-
dtype=None,
|
| 86 |
-
):
|
| 87 |
-
from ....modules.backends.triton_ascend.fused_linear_cross_entropy import (
|
| 88 |
-
logsumexp_fwd_npu,
|
| 89 |
-
)
|
| 90 |
-
return logsumexp_fwd_npu(x, scale=scale, softcapping=softcapping, dtype=dtype)
|
| 91 |
-
|
| 92 |
-
def fused_linear_cross_entropy_forward(
|
| 93 |
-
self,
|
| 94 |
-
x,
|
| 95 |
-
target,
|
| 96 |
-
weight,
|
| 97 |
-
bias=None,
|
| 98 |
-
ignore_index=-100,
|
| 99 |
-
label_smoothing=0.0,
|
| 100 |
-
logit_scale=1.0,
|
| 101 |
-
logit_softcapping=None,
|
| 102 |
-
num_chunks=8,
|
| 103 |
-
reduction="mean",
|
| 104 |
-
use_l2warp=False,
|
| 105 |
-
l2_penalty_factor=1e-4,
|
| 106 |
-
accumulate_grad_in_fp32=True,
|
| 107 |
-
):
|
| 108 |
-
from ....modules.backends.triton_ascend.fused_linear_cross_entropy import (
|
| 109 |
-
fused_linear_cross_entropy_forward_npu,
|
| 110 |
-
)
|
| 111 |
-
return fused_linear_cross_entropy_forward_npu(
|
| 112 |
-
x,
|
| 113 |
-
target,
|
| 114 |
-
weight,
|
| 115 |
-
bias,
|
| 116 |
-
ignore_index,
|
| 117 |
-
label_smoothing,
|
| 118 |
-
logit_scale,
|
| 119 |
-
logit_softcapping,
|
| 120 |
-
num_chunks,
|
| 121 |
-
reduction,
|
| 122 |
-
use_l2warp,
|
| 123 |
-
l2_penalty_factor,
|
| 124 |
-
accumulate_grad_in_fp32,
|
| 125 |
-
)
|
| 126 |
-
|
| 127 |
-
def fused_linear_cross_entropy_backward(
|
| 128 |
-
self,
|
| 129 |
-
do,
|
| 130 |
-
dx,
|
| 131 |
-
dw,
|
| 132 |
-
db,
|
| 133 |
-
):
|
| 134 |
-
from ....modules.backends.triton_ascend.fused_linear_cross_entropy import (
|
| 135 |
-
fused_linear_cross_entropy_backward_npu,
|
| 136 |
-
)
|
| 137 |
-
return fused_linear_cross_entropy_backward_npu(do, dx, dw, db)
|
| 138 |
-
|
| 139 |
-
def sigmoid_fwd(self, x, output_contiguous=False):
|
| 140 |
-
from ....modules.backends.triton_ascend.activations import sigmoid_fwd_npu
|
| 141 |
-
return sigmoid_fwd_npu(x, output_contiguous=output_contiguous)
|
| 142 |
-
|
| 143 |
-
def sigmoid_bwd(self, x, dy, output_contiguous=False):
|
| 144 |
-
from ....modules.backends.triton_ascend.activations import sigmoid_bwd_npu
|
| 145 |
-
return sigmoid_bwd_npu(x, dy, output_contiguous=output_contiguous)
|
| 146 |
-
|
| 147 |
-
def logsigmoid_fwd(self, x, temperature=1., output_contiguous=False):
|
| 148 |
-
from ....modules.backends.triton_ascend.activations import logsigmoid_fwd_npu
|
| 149 |
-
return logsigmoid_fwd_npu(x, temperature=temperature, output_contiguous=output_contiguous)
|
| 150 |
-
|
| 151 |
-
def logsigmoid_bwd(self, x, dy, temperature=1., output_contiguous=False):
|
| 152 |
-
from ....modules.backends.triton_ascend.activations import logsigmoid_bwd_npu
|
| 153 |
-
return logsigmoid_bwd_npu(x, dy, temperature=temperature, output_contiguous=output_contiguous)
|
| 154 |
-
|
| 155 |
-
def swish_fwd(self, x, output_contiguous=False):
|
| 156 |
-
from ....modules.backends.triton_ascend.activations import swish_fwd_npu
|
| 157 |
-
return swish_fwd_npu(x, output_contiguous=output_contiguous)
|
| 158 |
-
|
| 159 |
-
def swish_bwd(self, x, dy, output_contiguous=False):
|
| 160 |
-
from ....modules.backends.triton_ascend.activations import swish_bwd_npu
|
| 161 |
-
return swish_bwd_npu(x, dy, output_contiguous=output_contiguous)
|
| 162 |
-
|
| 163 |
-
def swiglu_fwd(self, x, y, output_contiguous=False):
|
| 164 |
-
from ....modules.backends.triton_ascend.activations import swiglu_fwd_npu
|
| 165 |
-
return swiglu_fwd_npu(x, y, output_contiguous=output_contiguous)
|
| 166 |
-
|
| 167 |
-
def swiglu_fwdbwd(self, x, y, g, use_weight=False, output_contiguous=False):
|
| 168 |
-
from ....modules.backends.triton_ascend.activations import swiglu_fwdbwd_npu
|
| 169 |
-
return swiglu_fwdbwd_npu(x, y, g, use_weight=use_weight, output_contiguous=output_contiguous)
|
| 170 |
-
|
| 171 |
-
def swiglu_linear(self, x, y, weight, bias):
|
| 172 |
-
from ....modules.backends.triton_ascend.activations import swiglu_linear_npu
|
| 173 |
-
return swiglu_linear_npu(x, y, weight, bias)
|
| 174 |
-
|
| 175 |
-
def gelu_fwd(self, x):
|
| 176 |
-
from ....modules.backends.triton_ascend.activations import gelu_fwd_npu
|
| 177 |
-
return gelu_fwd_npu(x)
|
| 178 |
-
|
| 179 |
-
def gelu_bwd(self, g, x):
|
| 180 |
-
from ....modules.backends.triton_ascend.activations import gelu_bwd_npu
|
| 181 |
-
return gelu_bwd_npu(g, x)
|
| 182 |
-
|
| 183 |
-
def sqrelu_fwd(self, x):
|
| 184 |
-
from ....modules.backends.triton_ascend.activations import sqrelu_fwd_npu
|
| 185 |
-
return sqrelu_fwd_npu(x)
|
| 186 |
-
|
| 187 |
-
def sqrelu_bwd(self, g, x):
|
| 188 |
-
from ....modules.backends.triton_ascend.activations import sqrelu_bwd_npu
|
| 189 |
-
return sqrelu_bwd_npu(g, x)
|
| 190 |
-
|
| 191 |
-
def powglu_fwd(self, x, y, power=3.0, output_contiguous=False):
|
| 192 |
-
from ....modules.backends.triton_ascend.activations import powglu_fwd_npu
|
| 193 |
-
return powglu_fwd_npu(x, y, power=power, output_contiguous=output_contiguous)
|
| 194 |
-
|
| 195 |
-
def powglu_fwdbwd(self, x, y, g, power=3.0, use_weight=False, output_contiguous=False):
|
| 196 |
-
from ....modules.backends.triton_ascend.activations import powglu_fwdbwd_npu
|
| 197 |
-
return powglu_fwdbwd_npu(
|
| 198 |
-
x, y, g, power=power, use_weight=use_weight, output_contiguous=output_contiguous,
|
| 199 |
-
)
|
| 200 |
-
|
| 201 |
-
def powglu_linear(self, x, y, weight, bias, power=3.0):
|
| 202 |
-
from ....modules.backends.triton_ascend.activations import powglu_linear_npu
|
| 203 |
-
return powglu_linear_npu(x, y, weight, bias, power)
|
| 204 |
-
|
| 205 |
-
def fused_kl_div_forward(
|
| 206 |
-
self,
|
| 207 |
-
x,
|
| 208 |
-
target_x,
|
| 209 |
-
weight,
|
| 210 |
-
target_weight,
|
| 211 |
-
reduction='batchmean',
|
| 212 |
-
accumulate_grad_in_fp32=True,
|
| 213 |
-
):
|
| 214 |
-
from ....modules.backends.triton_ascend.fused_kl_div import fused_kl_div_forward_npu
|
| 215 |
-
return fused_kl_div_forward_npu(
|
| 216 |
-
x,
|
| 217 |
-
target_x,
|
| 218 |
-
weight,
|
| 219 |
-
target_weight,
|
| 220 |
-
reduction,
|
| 221 |
-
accumulate_grad_in_fp32,
|
| 222 |
-
)
|
| 223 |
-
|
| 224 |
-
def fused_kl_div_backward(self, do, dx, dw):
|
| 225 |
-
from ....modules.backends.triton_ascend.fused_kl_div import fused_kl_div_backward_npu
|
| 226 |
-
return fused_kl_div_backward_npu(do, dx, dw)
|
| 227 |
-
|
| 228 |
-
def layer_norm_fwd(
|
| 229 |
-
self,
|
| 230 |
-
x,
|
| 231 |
-
weight,
|
| 232 |
-
bias,
|
| 233 |
-
eps=1e-5,
|
| 234 |
-
residual=None,
|
| 235 |
-
out_dtype=None,
|
| 236 |
-
residual_dtype=None,
|
| 237 |
-
is_rms_norm=False,
|
| 238 |
-
num_groups=1,
|
| 239 |
-
):
|
| 240 |
-
from ....modules.backends.triton_ascend.layernorm import layer_norm_fwd_npu
|
| 241 |
-
return layer_norm_fwd_npu(
|
| 242 |
-
x,
|
| 243 |
-
weight,
|
| 244 |
-
bias,
|
| 245 |
-
eps,
|
| 246 |
-
residual,
|
| 247 |
-
out_dtype,
|
| 248 |
-
residual_dtype,
|
| 249 |
-
is_rms_norm,
|
| 250 |
-
num_groups,
|
| 251 |
-
)
|
| 252 |
-
|
| 253 |
-
def layer_norm_bwd(
|
| 254 |
-
self,
|
| 255 |
-
dy,
|
| 256 |
-
x,
|
| 257 |
-
weight,
|
| 258 |
-
bias,
|
| 259 |
-
mean=None,
|
| 260 |
-
rstd=None,
|
| 261 |
-
dres=None,
|
| 262 |
-
has_residual=False,
|
| 263 |
-
is_rms_norm=False,
|
| 264 |
-
x_dtype=None,
|
| 265 |
-
recompute_output=False,
|
| 266 |
-
num_groups=1,
|
| 267 |
-
):
|
| 268 |
-
from ....modules.backends.triton_ascend.layernorm import layer_norm_bwd_npu
|
| 269 |
-
return layer_norm_bwd_npu(
|
| 270 |
-
dy,
|
| 271 |
-
x,
|
| 272 |
-
weight,
|
| 273 |
-
bias,
|
| 274 |
-
mean,
|
| 275 |
-
rstd,
|
| 276 |
-
dres,
|
| 277 |
-
has_residual,
|
| 278 |
-
is_rms_norm,
|
| 279 |
-
x_dtype,
|
| 280 |
-
recompute_output,
|
| 281 |
-
num_groups,
|
| 282 |
-
)
|
| 283 |
-
|
| 284 |
-
def fused_grpo_loss(
|
| 285 |
-
self,
|
| 286 |
-
logits,
|
| 287 |
-
ref_logp,
|
| 288 |
-
input_ids,
|
| 289 |
-
advantages,
|
| 290 |
-
beta=0.1,
|
| 291 |
-
completion_mask=None,
|
| 292 |
-
save_kl=False,
|
| 293 |
-
inplace=False,
|
| 294 |
-
):
|
| 295 |
-
from ....modules.backends.triton_ascend.grpo import fused_grpo_loss_npu
|
| 296 |
-
return fused_grpo_loss_npu(
|
| 297 |
-
logits,
|
| 298 |
-
ref_logp,
|
| 299 |
-
input_ids,
|
| 300 |
-
advantages,
|
| 301 |
-
beta,
|
| 302 |
-
completion_mask,
|
| 303 |
-
save_kl,
|
| 304 |
-
inplace,
|
| 305 |
-
)
|
| 306 |
-
|
| 307 |
-
def causal_conv1d_fwd(
|
| 308 |
-
self,
|
| 309 |
-
x,
|
| 310 |
-
weight,
|
| 311 |
-
bias,
|
| 312 |
-
residual,
|
| 313 |
-
initial_state=None,
|
| 314 |
-
output_final_state=False,
|
| 315 |
-
activation=None,
|
| 316 |
-
cu_seqlens=None,
|
| 317 |
-
cu_seqlens_cpu=None,
|
| 318 |
-
chunk_indices=None,
|
| 319 |
-
BT=64,
|
| 320 |
-
layout_fallback=False,
|
| 321 |
-
):
|
| 322 |
-
from ....modules.backends.triton_ascend.causal_conv1d import causal_conv1d_fwd_npu
|
| 323 |
-
return causal_conv1d_fwd_npu(
|
| 324 |
-
x,
|
| 325 |
-
weight,
|
| 326 |
-
bias,
|
| 327 |
-
residual,
|
| 328 |
-
initial_state,
|
| 329 |
-
output_final_state,
|
| 330 |
-
activation,
|
| 331 |
-
cu_seqlens,
|
| 332 |
-
cu_seqlens_cpu,
|
| 333 |
-
chunk_indices,
|
| 334 |
-
BT,
|
| 335 |
-
layout_fallback,
|
| 336 |
-
)
|
| 337 |
-
|
| 338 |
-
def causal_conv1d_bwd(
|
| 339 |
-
self,
|
| 340 |
-
x,
|
| 341 |
-
dy,
|
| 342 |
-
dht,
|
| 343 |
-
weight=None,
|
| 344 |
-
bias=None,
|
| 345 |
-
residual=None,
|
| 346 |
-
initial_state=None,
|
| 347 |
-
activation=None,
|
| 348 |
-
cu_seqlens=None,
|
| 349 |
-
cu_seqlens_cpu=None,
|
| 350 |
-
chunk_indices=None,
|
| 351 |
-
BT=64,
|
| 352 |
-
layout_fallback=False,
|
| 353 |
-
):
|
| 354 |
-
from ....modules.backends.triton_ascend.causal_conv1d import causal_conv1d_bwd_npu
|
| 355 |
-
return causal_conv1d_bwd_npu(
|
| 356 |
-
x,
|
| 357 |
-
dy,
|
| 358 |
-
dht,
|
| 359 |
-
weight,
|
| 360 |
-
bias,
|
| 361 |
-
residual,
|
| 362 |
-
initial_state,
|
| 363 |
-
activation,
|
| 364 |
-
cu_seqlens,
|
| 365 |
-
cu_seqlens_cpu,
|
| 366 |
-
chunk_indices,
|
| 367 |
-
BT,
|
| 368 |
-
layout_fallback,
|
| 369 |
-
)
|
| 370 |
-
|
| 371 |
-
def compute_dh0_triton(
|
| 372 |
-
self,
|
| 373 |
-
dy,
|
| 374 |
-
y,
|
| 375 |
-
weight,
|
| 376 |
-
initial_state,
|
| 377 |
-
activation,
|
| 378 |
-
cu_seqlens,
|
| 379 |
-
):
|
| 380 |
-
from ....modules.backends.triton_ascend.causal_conv1d import compute_dh0_npu
|
| 381 |
-
return compute_dh0_npu(
|
| 382 |
-
dy,
|
| 383 |
-
y,
|
| 384 |
-
weight,
|
| 385 |
-
initial_state,
|
| 386 |
-
activation,
|
| 387 |
-
cu_seqlens,
|
| 388 |
-
)
|
| 389 |
-
|
| 390 |
-
def causal_conv1d_update_states(
|
| 391 |
-
self,
|
| 392 |
-
x,
|
| 393 |
-
state_len,
|
| 394 |
-
initial_state=None,
|
| 395 |
-
cu_seqlens=None,
|
| 396 |
-
):
|
| 397 |
-
from ....modules.backends.triton_ascend.causal_conv1d import causal_conv1d_update_states_npu
|
| 398 |
-
return causal_conv1d_update_states_npu(
|
| 399 |
-
x,
|
| 400 |
-
state_len,
|
| 401 |
-
initial_state,
|
| 402 |
-
cu_seqlens,
|
| 403 |
-
)
|
| 404 |
-
|
| 405 |
-
def causal_conv1d_update(
|
| 406 |
-
self,
|
| 407 |
-
x,
|
| 408 |
-
cache,
|
| 409 |
-
residual=None,
|
| 410 |
-
weight=None,
|
| 411 |
-
bias=None,
|
| 412 |
-
activation=None,
|
| 413 |
-
):
|
| 414 |
-
from ....modules.backends.triton_ascend.causal_conv1d import causal_conv1d_update_npu
|
| 415 |
-
return causal_conv1d_update_npu(
|
| 416 |
-
x,
|
| 417 |
-
cache,
|
| 418 |
-
residual,
|
| 419 |
-
weight,
|
| 420 |
-
bias,
|
| 421 |
-
activation,
|
| 422 |
-
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
build/torch-cuda/modules/backends/triton_ascend/activations.py
DELETED
|
@@ -1,931 +0,0 @@
|
|
| 1 |
-
# Copyright (c) 2023-2026, Songlin Yang, Yu Zhang, Zhiyuan Li
|
| 2 |
-
#
|
| 3 |
-
# This source code is licensed under the MIT license found in the
|
| 4 |
-
# LICENSE file in the root directory of this source tree.
|
| 5 |
-
# For a list of all contributors, visit:
|
| 6 |
-
# https://github.com/fla-org/flash-linear-attention/graphs/contributors
|
| 7 |
-
|
| 8 |
-
"""Activation kernels adapted for triton-ascend on Huawei NPU."""
|
| 9 |
-
|
| 10 |
-
import torch
|
| 11 |
-
import torch.nn.functional as F
|
| 12 |
-
import triton
|
| 13 |
-
import triton.language as tl
|
| 14 |
-
|
| 15 |
-
from ....ops.utils.op import exp, log
|
| 16 |
-
from ....utils import autocast_custom_bwd, autocast_custom_fwd, input_guard
|
| 17 |
-
from ....utils.ascend_ub_manager import ASCEND_MAX_GRID_DIM, compute_activation_block_size
|
| 18 |
-
|
| 19 |
-
# Ascend launch limits: grid dim and per-core vector width.
|
| 20 |
-
_MAX_CORE_DIM = 65535
|
| 21 |
-
|
| 22 |
-
|
| 23 |
-
def _activation_launch_config(
|
| 24 |
-
T: int,
|
| 25 |
-
is_backward: bool = False,
|
| 26 |
-
*,
|
| 27 |
-
memory_multiplier: float | None = None,
|
| 28 |
-
) -> tuple[tuple[int], int]:
|
| 29 |
-
"""Pick block size under Ascend launch and UB limits."""
|
| 30 |
-
B = compute_activation_block_size(
|
| 31 |
-
T,
|
| 32 |
-
is_backward,
|
| 33 |
-
max_grid=ASCEND_MAX_GRID_DIM,
|
| 34 |
-
max_core_dim=_MAX_CORE_DIM,
|
| 35 |
-
memory_multiplier=memory_multiplier,
|
| 36 |
-
)
|
| 37 |
-
return (triton.cdiv(T, B),), B
|
| 38 |
-
|
| 39 |
-
|
| 40 |
-
@triton.jit
|
| 41 |
-
def _flat_offset(
|
| 42 |
-
offs,
|
| 43 |
-
D: tl.constexpr,
|
| 44 |
-
stride,
|
| 45 |
-
IS_LINEAR: tl.constexpr,
|
| 46 |
-
):
|
| 47 |
-
if IS_LINEAR:
|
| 48 |
-
return offs
|
| 49 |
-
row = offs // D
|
| 50 |
-
col = offs % D
|
| 51 |
-
return row * stride + col
|
| 52 |
-
|
| 53 |
-
|
| 54 |
-
def _get_stride(x: torch.Tensor) -> int:
|
| 55 |
-
if x.ndim < 2:
|
| 56 |
-
return 0
|
| 57 |
-
return x.stride(-2)
|
| 58 |
-
|
| 59 |
-
|
| 60 |
-
def _is_linear_stride(stride: int, D: int) -> bool:
|
| 61 |
-
return stride == D
|
| 62 |
-
|
| 63 |
-
|
| 64 |
-
_LINEAR_HEURISTICS_XY = {
|
| 65 |
-
'X_LINEAR': lambda args: _is_linear_stride(args['stride_x_row'], args['D']),
|
| 66 |
-
'Y_LINEAR': lambda args: _is_linear_stride(args['stride_y_row'], args['D']),
|
| 67 |
-
}
|
| 68 |
-
|
| 69 |
-
_LINEAR_HEURISTICS_XYZ = {
|
| 70 |
-
**_LINEAR_HEURISTICS_XY,
|
| 71 |
-
'Z_LINEAR': lambda args: _is_linear_stride(args['stride_z_row'], args['D']),
|
| 72 |
-
}
|
| 73 |
-
|
| 74 |
-
_LINEAR_HEURISTICS_BWD = {
|
| 75 |
-
'X_LINEAR': lambda args: _is_linear_stride(args['stride_x_row'], args['D']),
|
| 76 |
-
'DY_LINEAR': lambda args: _is_linear_stride(args['stride_dy_row'], args['D']),
|
| 77 |
-
'DX_LINEAR': lambda args: _is_linear_stride(args['stride_dx_row'], args['D']),
|
| 78 |
-
}
|
| 79 |
-
|
| 80 |
-
_LINEAR_HEURISTICS_FWDBWD = {
|
| 81 |
-
**_LINEAR_HEURISTICS_XYZ,
|
| 82 |
-
'G_LINEAR': lambda args: _is_linear_stride(args['stride_g_row'], args['D']),
|
| 83 |
-
'DX_LINEAR': lambda args: _is_linear_stride(args['stride_dx_row'], args['D']),
|
| 84 |
-
'DY_LINEAR': lambda args: _is_linear_stride(args['stride_dy_row'], args['D']),
|
| 85 |
-
}
|
| 86 |
-
|
| 87 |
-
|
| 88 |
-
def _is_inner_contiguous(x: torch.Tensor) -> bool:
|
| 89 |
-
ndim = x.ndim
|
| 90 |
-
if ndim < 2:
|
| 91 |
-
return True
|
| 92 |
-
if x.stride(-1) != 1:
|
| 93 |
-
return False
|
| 94 |
-
if ndim == 2:
|
| 95 |
-
return True
|
| 96 |
-
if ndim == 3:
|
| 97 |
-
return x.stride(0) == x.stride(-2) * x.shape[-2]
|
| 98 |
-
if ndim == 4:
|
| 99 |
-
if x.stride(1) != x.stride(-2) * x.shape[-2]:
|
| 100 |
-
return False
|
| 101 |
-
return x.stride(0) == x.stride(1) * x.shape[1]
|
| 102 |
-
expected = x.stride(-2) * x.shape[-2]
|
| 103 |
-
for d in range(ndim - 3, -1, -1):
|
| 104 |
-
if x.stride(d) != expected:
|
| 105 |
-
return False
|
| 106 |
-
expected *= x.shape[d]
|
| 107 |
-
return True
|
| 108 |
-
|
| 109 |
-
|
| 110 |
-
def _ensure_inner_contiguous(x: torch.Tensor) -> torch.Tensor:
|
| 111 |
-
if _is_inner_contiguous(x):
|
| 112 |
-
return x
|
| 113 |
-
return x.contiguous()
|
| 114 |
-
|
| 115 |
-
|
| 116 |
-
def _alloc_output(x: torch.Tensor, contiguous: bool = False) -> torch.Tensor:
|
| 117 |
-
if contiguous:
|
| 118 |
-
return x.new_empty(x.shape)
|
| 119 |
-
return torch.empty_like(x)
|
| 120 |
-
|
| 121 |
-
|
| 122 |
-
@triton.heuristics(_LINEAR_HEURISTICS_XY)
|
| 123 |
-
@triton.jit(do_not_specialize=['T'])
|
| 124 |
-
def sigmoid_fwd_kernel(
|
| 125 |
-
x, y,
|
| 126 |
-
T,
|
| 127 |
-
D: tl.constexpr,
|
| 128 |
-
stride_x_row,
|
| 129 |
-
stride_y_row,
|
| 130 |
-
B: tl.constexpr,
|
| 131 |
-
X_LINEAR: tl.constexpr,
|
| 132 |
-
Y_LINEAR: tl.constexpr,
|
| 133 |
-
):
|
| 134 |
-
pid = tl.program_id(0)
|
| 135 |
-
offs = pid * B + tl.arange(0, B)
|
| 136 |
-
mask = offs < T
|
| 137 |
-
x_off = _flat_offset(offs, D, stride_x_row, X_LINEAR)
|
| 138 |
-
y_off = _flat_offset(offs, D, stride_y_row, Y_LINEAR)
|
| 139 |
-
x_val = tl.load(x + x_off, mask=mask, other=0.).to(tl.float32)
|
| 140 |
-
y_val = tl.sigmoid(x_val)
|
| 141 |
-
tl.store(y + y_off, y_val.to(y.dtype.element_ty), mask=mask)
|
| 142 |
-
|
| 143 |
-
|
| 144 |
-
@triton.heuristics(_LINEAR_HEURISTICS_BWD)
|
| 145 |
-
@triton.jit(do_not_specialize=['T'])
|
| 146 |
-
def sigmoid_bwd_kernel(
|
| 147 |
-
x, dy, dx,
|
| 148 |
-
T,
|
| 149 |
-
D: tl.constexpr,
|
| 150 |
-
stride_x_row,
|
| 151 |
-
stride_dy_row,
|
| 152 |
-
stride_dx_row,
|
| 153 |
-
B: tl.constexpr,
|
| 154 |
-
X_LINEAR: tl.constexpr,
|
| 155 |
-
DY_LINEAR: tl.constexpr,
|
| 156 |
-
DX_LINEAR: tl.constexpr,
|
| 157 |
-
):
|
| 158 |
-
pid = tl.program_id(0)
|
| 159 |
-
offs = pid * B + tl.arange(0, B)
|
| 160 |
-
mask = offs < T
|
| 161 |
-
x_off = _flat_offset(offs, D, stride_x_row, X_LINEAR)
|
| 162 |
-
dy_off = _flat_offset(offs, D, stride_dy_row, DY_LINEAR)
|
| 163 |
-
dx_off = _flat_offset(offs, D, stride_dx_row, DX_LINEAR)
|
| 164 |
-
x_val = tl.load(x + x_off, mask=mask, other=0.).to(tl.float32)
|
| 165 |
-
g_val = tl.load(dy + dy_off, mask=mask, other=0.).to(tl.float32)
|
| 166 |
-
s = tl.sigmoid(x_val)
|
| 167 |
-
dx_val = g_val * s * (1.0 - s)
|
| 168 |
-
tl.store(dx + dx_off, dx_val.to(dx.dtype.element_ty), mask=mask)
|
| 169 |
-
|
| 170 |
-
|
| 171 |
-
@triton.heuristics(_LINEAR_HEURISTICS_XY)
|
| 172 |
-
@triton.jit(do_not_specialize=['T'])
|
| 173 |
-
def logsigmoid_fwd_kernel(
|
| 174 |
-
x,
|
| 175 |
-
y,
|
| 176 |
-
temperature,
|
| 177 |
-
T,
|
| 178 |
-
D: tl.constexpr,
|
| 179 |
-
stride_x_row,
|
| 180 |
-
stride_y_row,
|
| 181 |
-
B: tl.constexpr,
|
| 182 |
-
X_LINEAR: tl.constexpr,
|
| 183 |
-
Y_LINEAR: tl.constexpr,
|
| 184 |
-
):
|
| 185 |
-
i = tl.program_id(0)
|
| 186 |
-
offs = i * B + tl.arange(0, B)
|
| 187 |
-
mask = offs < T
|
| 188 |
-
x_off = _flat_offset(offs, D, stride_x_row, X_LINEAR)
|
| 189 |
-
y_off = _flat_offset(offs, D, stride_y_row, Y_LINEAR)
|
| 190 |
-
|
| 191 |
-
b_x = tl.load(x + x_off, mask=mask, other=0.).to(tl.float32)
|
| 192 |
-
b_m = tl.minimum(0., b_x)
|
| 193 |
-
b_z = 1. + exp(-tl.abs(b_x))
|
| 194 |
-
b_y = (b_m - log(b_z)) / temperature
|
| 195 |
-
tl.store(y + y_off, b_y.to(y.dtype.element_ty), mask=mask)
|
| 196 |
-
|
| 197 |
-
|
| 198 |
-
@triton.heuristics(_LINEAR_HEURISTICS_BWD)
|
| 199 |
-
@triton.jit(do_not_specialize=['T'])
|
| 200 |
-
def logsigmoid_bwd_kernel(
|
| 201 |
-
x,
|
| 202 |
-
dx,
|
| 203 |
-
dy,
|
| 204 |
-
temperature,
|
| 205 |
-
T,
|
| 206 |
-
D: tl.constexpr,
|
| 207 |
-
stride_x_row,
|
| 208 |
-
stride_dx_row,
|
| 209 |
-
stride_dy_row,
|
| 210 |
-
B: tl.constexpr,
|
| 211 |
-
X_LINEAR: tl.constexpr,
|
| 212 |
-
DX_LINEAR: tl.constexpr,
|
| 213 |
-
DY_LINEAR: tl.constexpr,
|
| 214 |
-
):
|
| 215 |
-
i = tl.program_id(0)
|
| 216 |
-
offs = i * B + tl.arange(0, B)
|
| 217 |
-
mask = offs < T
|
| 218 |
-
x_off = _flat_offset(offs, D, stride_x_row, X_LINEAR)
|
| 219 |
-
dx_off = _flat_offset(offs, D, stride_dx_row, DX_LINEAR)
|
| 220 |
-
dy_off = _flat_offset(offs, D, stride_dy_row, DY_LINEAR)
|
| 221 |
-
|
| 222 |
-
b_x = tl.load(x + x_off, mask=mask, other=0.).to(tl.float32)
|
| 223 |
-
b_dy = tl.load(dy + dy_off, mask=mask, other=0.).to(tl.float32)
|
| 224 |
-
b_s = tl.sigmoid(b_x)
|
| 225 |
-
b_dx = b_dy * ((1. - b_s) / temperature)
|
| 226 |
-
tl.store(dx + dx_off, b_dx.to(dx.dtype.element_ty), mask=mask)
|
| 227 |
-
|
| 228 |
-
|
| 229 |
-
@triton.heuristics(_LINEAR_HEURISTICS_XY)
|
| 230 |
-
@triton.jit(do_not_specialize=['T'])
|
| 231 |
-
def swish_fwd_kernel(
|
| 232 |
-
x, y,
|
| 233 |
-
T,
|
| 234 |
-
D: tl.constexpr,
|
| 235 |
-
stride_x_row,
|
| 236 |
-
stride_y_row,
|
| 237 |
-
B: tl.constexpr,
|
| 238 |
-
X_LINEAR: tl.constexpr,
|
| 239 |
-
Y_LINEAR: tl.constexpr,
|
| 240 |
-
):
|
| 241 |
-
pid = tl.program_id(0)
|
| 242 |
-
offs = pid * B + tl.arange(0, B)
|
| 243 |
-
mask = offs < T
|
| 244 |
-
x_off = _flat_offset(offs, D, stride_x_row, X_LINEAR)
|
| 245 |
-
y_off = _flat_offset(offs, D, stride_y_row, Y_LINEAR)
|
| 246 |
-
x_val = tl.load(x + x_off, mask=mask, other=0.).to(tl.float32)
|
| 247 |
-
s = tl.sigmoid(x_val)
|
| 248 |
-
y_val = x_val * s
|
| 249 |
-
tl.store(y + y_off, y_val.to(y.dtype.element_ty), mask=mask)
|
| 250 |
-
|
| 251 |
-
|
| 252 |
-
@triton.heuristics(_LINEAR_HEURISTICS_BWD)
|
| 253 |
-
@triton.jit(do_not_specialize=['T'])
|
| 254 |
-
def swish_bwd_kernel(
|
| 255 |
-
x, dy, dx,
|
| 256 |
-
T,
|
| 257 |
-
D: tl.constexpr,
|
| 258 |
-
stride_x_row,
|
| 259 |
-
stride_dy_row,
|
| 260 |
-
stride_dx_row,
|
| 261 |
-
B: tl.constexpr,
|
| 262 |
-
X_LINEAR: tl.constexpr,
|
| 263 |
-
DY_LINEAR: tl.constexpr,
|
| 264 |
-
DX_LINEAR: tl.constexpr,
|
| 265 |
-
):
|
| 266 |
-
pid = tl.program_id(0)
|
| 267 |
-
offs = pid * B + tl.arange(0, B)
|
| 268 |
-
mask = offs < T
|
| 269 |
-
x_off = _flat_offset(offs, D, stride_x_row, X_LINEAR)
|
| 270 |
-
dy_off = _flat_offset(offs, D, stride_dy_row, DY_LINEAR)
|
| 271 |
-
dx_off = _flat_offset(offs, D, stride_dx_row, DX_LINEAR)
|
| 272 |
-
x_val = tl.load(x + x_off, mask=mask, other=0.).to(tl.float32)
|
| 273 |
-
g_val = tl.load(dy + dy_off, mask=mask, other=0.).to(tl.float32)
|
| 274 |
-
s = tl.sigmoid(x_val)
|
| 275 |
-
dx_val = g_val * s * (1.0 + x_val * (1.0 - s))
|
| 276 |
-
tl.store(dx + dx_off, dx_val.to(dx.dtype.element_ty), mask=mask)
|
| 277 |
-
|
| 278 |
-
|
| 279 |
-
@triton.heuristics(_LINEAR_HEURISTICS_XYZ)
|
| 280 |
-
@triton.jit(do_not_specialize=['T'])
|
| 281 |
-
def swiglu_fwd_kernel(
|
| 282 |
-
x, y, z,
|
| 283 |
-
T,
|
| 284 |
-
D: tl.constexpr,
|
| 285 |
-
stride_x_row,
|
| 286 |
-
stride_y_row,
|
| 287 |
-
stride_z_row,
|
| 288 |
-
B: tl.constexpr,
|
| 289 |
-
X_LINEAR: tl.constexpr,
|
| 290 |
-
Y_LINEAR: tl.constexpr,
|
| 291 |
-
Z_LINEAR: tl.constexpr,
|
| 292 |
-
):
|
| 293 |
-
pid = tl.program_id(0)
|
| 294 |
-
offs = pid * B + tl.arange(0, B)
|
| 295 |
-
mask = offs < T
|
| 296 |
-
x_off = _flat_offset(offs, D, stride_x_row, X_LINEAR)
|
| 297 |
-
y_off = _flat_offset(offs, D, stride_y_row, Y_LINEAR)
|
| 298 |
-
z_off = _flat_offset(offs, D, stride_z_row, Z_LINEAR)
|
| 299 |
-
x_val = tl.load(x + x_off, mask=mask, other=0.).to(tl.float32)
|
| 300 |
-
y_val = tl.load(y + y_off, mask=mask, other=0.).to(tl.float32)
|
| 301 |
-
s = tl.sigmoid(x_val)
|
| 302 |
-
z_val = x_val * s * y_val
|
| 303 |
-
tl.store(z + z_off, z_val.to(z.dtype.element_ty), mask=mask)
|
| 304 |
-
|
| 305 |
-
|
| 306 |
-
@triton.heuristics({
|
| 307 |
-
'HAS_WEIGHT': lambda args: args['z'] is not None,
|
| 308 |
-
**_LINEAR_HEURISTICS_FWDBWD,
|
| 309 |
-
})
|
| 310 |
-
@triton.jit(do_not_specialize=['T'])
|
| 311 |
-
def swiglu_fwdbwd_kernel(
|
| 312 |
-
x, y, g, dx, dy, z,
|
| 313 |
-
T,
|
| 314 |
-
D: tl.constexpr,
|
| 315 |
-
stride_x_row,
|
| 316 |
-
stride_y_row,
|
| 317 |
-
stride_g_row,
|
| 318 |
-
stride_dx_row,
|
| 319 |
-
stride_dy_row,
|
| 320 |
-
stride_z_row,
|
| 321 |
-
B: tl.constexpr,
|
| 322 |
-
HAS_WEIGHT: tl.constexpr,
|
| 323 |
-
X_LINEAR: tl.constexpr,
|
| 324 |
-
Y_LINEAR: tl.constexpr,
|
| 325 |
-
G_LINEAR: tl.constexpr,
|
| 326 |
-
DX_LINEAR: tl.constexpr,
|
| 327 |
-
DY_LINEAR: tl.constexpr,
|
| 328 |
-
Z_LINEAR: tl.constexpr,
|
| 329 |
-
):
|
| 330 |
-
pid = tl.program_id(0)
|
| 331 |
-
offs = pid * B + tl.arange(0, B)
|
| 332 |
-
mask = offs < T
|
| 333 |
-
x_off = _flat_offset(offs, D, stride_x_row, X_LINEAR)
|
| 334 |
-
y_off = _flat_offset(offs, D, stride_y_row, Y_LINEAR)
|
| 335 |
-
g_off = _flat_offset(offs, D, stride_g_row, G_LINEAR)
|
| 336 |
-
dx_off = _flat_offset(offs, D, stride_dx_row, DX_LINEAR)
|
| 337 |
-
dy_off = _flat_offset(offs, D, stride_dy_row, DY_LINEAR)
|
| 338 |
-
x_val = tl.load(x + x_off, mask=mask, other=0.).to(tl.float32)
|
| 339 |
-
y_val = tl.load(y + y_off, mask=mask, other=0.).to(tl.float32)
|
| 340 |
-
g_val = tl.load(g + g_off, mask=mask, other=0.).to(tl.float32)
|
| 341 |
-
|
| 342 |
-
s = tl.sigmoid(x_val)
|
| 343 |
-
x_s = x_val * s
|
| 344 |
-
dx_val = g_val * s * (1.0 + x_val * (1.0 - s)) * y_val
|
| 345 |
-
dy_val = g_val * x_s
|
| 346 |
-
|
| 347 |
-
tl.store(dx + dx_off, dx_val.to(dx.dtype.element_ty), mask=mask)
|
| 348 |
-
tl.store(dy + dy_off, dy_val.to(dy.dtype.element_ty), mask=mask)
|
| 349 |
-
if HAS_WEIGHT:
|
| 350 |
-
z_off = _flat_offset(offs, D, stride_z_row, Z_LINEAR)
|
| 351 |
-
z_val = x_s * y_val
|
| 352 |
-
tl.store(z + z_off, z_val.to(z.dtype.element_ty), mask=mask)
|
| 353 |
-
|
| 354 |
-
|
| 355 |
-
@triton.heuristics(_LINEAR_HEURISTICS_XY)
|
| 356 |
-
@triton.jit(do_not_specialize=['T'])
|
| 357 |
-
def gelu_fwd_kernel(
|
| 358 |
-
x, y,
|
| 359 |
-
T,
|
| 360 |
-
D: tl.constexpr,
|
| 361 |
-
stride_x_row,
|
| 362 |
-
stride_y_row,
|
| 363 |
-
B: tl.constexpr,
|
| 364 |
-
X_LINEAR: tl.constexpr,
|
| 365 |
-
Y_LINEAR: tl.constexpr,
|
| 366 |
-
):
|
| 367 |
-
pid = tl.program_id(0)
|
| 368 |
-
offs = pid * B + tl.arange(0, B)
|
| 369 |
-
mask = offs < T
|
| 370 |
-
x_off = _flat_offset(offs, D, stride_x_row, X_LINEAR)
|
| 371 |
-
y_off = _flat_offset(offs, D, stride_y_row, Y_LINEAR)
|
| 372 |
-
x_val = tl.load(x + x_off, mask=mask, other=0.).to(tl.float32)
|
| 373 |
-
t = 0.79788456 * x_val * (1.0 + 0.044715 * x_val * x_val)
|
| 374 |
-
tanh_out = tl.tanh(t)
|
| 375 |
-
y_val = x_val * 0.5 * (1.0 + tanh_out)
|
| 376 |
-
tl.store(y + y_off, y_val.to(y.dtype.element_ty), mask=mask)
|
| 377 |
-
|
| 378 |
-
|
| 379 |
-
@triton.heuristics(_LINEAR_HEURISTICS_BWD)
|
| 380 |
-
@triton.jit(do_not_specialize=['T'])
|
| 381 |
-
def gelu_bwd_kernel(
|
| 382 |
-
x, dy, dx,
|
| 383 |
-
T,
|
| 384 |
-
D: tl.constexpr,
|
| 385 |
-
stride_x_row,
|
| 386 |
-
stride_dy_row,
|
| 387 |
-
stride_dx_row,
|
| 388 |
-
B: tl.constexpr,
|
| 389 |
-
X_LINEAR: tl.constexpr,
|
| 390 |
-
DY_LINEAR: tl.constexpr,
|
| 391 |
-
DX_LINEAR: tl.constexpr,
|
| 392 |
-
):
|
| 393 |
-
pid = tl.program_id(0)
|
| 394 |
-
offs = pid * B + tl.arange(0, B)
|
| 395 |
-
mask = offs < T
|
| 396 |
-
x_off = _flat_offset(offs, D, stride_x_row, X_LINEAR)
|
| 397 |
-
dy_off = _flat_offset(offs, D, stride_dy_row, DY_LINEAR)
|
| 398 |
-
dx_off = _flat_offset(offs, D, stride_dx_row, DX_LINEAR)
|
| 399 |
-
x_val = tl.load(x + x_off, mask=mask, other=0.).to(tl.float32)
|
| 400 |
-
g_val = tl.load(dy + dy_off, mask=mask, other=0.).to(tl.float32)
|
| 401 |
-
t = 0.79788456 * x_val * (1.0 + 0.044715 * x_val * x_val)
|
| 402 |
-
tanh_out = tl.tanh(t)
|
| 403 |
-
ff = 0.5 * x_val * (
|
| 404 |
-
(1.0 - tanh_out * tanh_out) * (0.79788456 + 0.1070322243 * x_val * x_val)
|
| 405 |
-
) + 0.5 * (1.0 + tanh_out)
|
| 406 |
-
dx_val = ff * g_val
|
| 407 |
-
tl.store(dx + dx_off, dx_val.to(dx.dtype.element_ty), mask=mask)
|
| 408 |
-
|
| 409 |
-
|
| 410 |
-
@triton.heuristics(_LINEAR_HEURISTICS_XY)
|
| 411 |
-
@triton.jit(do_not_specialize=['T'])
|
| 412 |
-
def sqrelu_fwd_kernel(
|
| 413 |
-
x, y,
|
| 414 |
-
T,
|
| 415 |
-
D: tl.constexpr,
|
| 416 |
-
stride_x_row,
|
| 417 |
-
stride_y_row,
|
| 418 |
-
B: tl.constexpr,
|
| 419 |
-
X_LINEAR: tl.constexpr,
|
| 420 |
-
Y_LINEAR: tl.constexpr,
|
| 421 |
-
):
|
| 422 |
-
pid = tl.program_id(0)
|
| 423 |
-
offs = pid * B + tl.arange(0, B)
|
| 424 |
-
mask = offs < T
|
| 425 |
-
x_off = _flat_offset(offs, D, stride_x_row, X_LINEAR)
|
| 426 |
-
y_off = _flat_offset(offs, D, stride_y_row, Y_LINEAR)
|
| 427 |
-
x_val = tl.load(x + x_off, mask=mask, other=0.).to(tl.float32)
|
| 428 |
-
r = tl.maximum(x_val, 0.0)
|
| 429 |
-
y_val = r * r
|
| 430 |
-
tl.store(y + y_off, y_val.to(y.dtype.element_ty), mask=mask)
|
| 431 |
-
|
| 432 |
-
|
| 433 |
-
@triton.heuristics(_LINEAR_HEURISTICS_BWD)
|
| 434 |
-
@triton.jit(do_not_specialize=['T'])
|
| 435 |
-
def sqrelu_bwd_kernel(
|
| 436 |
-
x, dy, dx,
|
| 437 |
-
T,
|
| 438 |
-
D: tl.constexpr,
|
| 439 |
-
stride_x_row,
|
| 440 |
-
stride_dy_row,
|
| 441 |
-
stride_dx_row,
|
| 442 |
-
B: tl.constexpr,
|
| 443 |
-
X_LINEAR: tl.constexpr,
|
| 444 |
-
DY_LINEAR: tl.constexpr,
|
| 445 |
-
DX_LINEAR: tl.constexpr,
|
| 446 |
-
):
|
| 447 |
-
pid = tl.program_id(0)
|
| 448 |
-
offs = pid * B + tl.arange(0, B)
|
| 449 |
-
mask = offs < T
|
| 450 |
-
x_off = _flat_offset(offs, D, stride_x_row, X_LINEAR)
|
| 451 |
-
dy_off = _flat_offset(offs, D, stride_dy_row, DY_LINEAR)
|
| 452 |
-
dx_off = _flat_offset(offs, D, stride_dx_row, DX_LINEAR)
|
| 453 |
-
x_val = tl.load(x + x_off, mask=mask, other=0.).to(tl.float32)
|
| 454 |
-
g_val = tl.load(dy + dy_off, mask=mask, other=0.).to(tl.float32)
|
| 455 |
-
dx_val = 2.0 * g_val * tl.maximum(x_val, 0.0)
|
| 456 |
-
tl.store(dx + dx_off, dx_val.to(dx.dtype.element_ty), mask=mask)
|
| 457 |
-
|
| 458 |
-
|
| 459 |
-
@torch.compiler.disable
|
| 460 |
-
def gelu_fwd_npu(x: torch.Tensor) -> torch.Tensor:
|
| 461 |
-
x = _ensure_inner_contiguous(x)
|
| 462 |
-
T, D = x.numel(), x.shape[-1]
|
| 463 |
-
y = _alloc_output(x)
|
| 464 |
-
grid, B = _activation_launch_config(T)
|
| 465 |
-
gelu_fwd_kernel[grid](
|
| 466 |
-
x, y, T=T, D=D,
|
| 467 |
-
stride_x_row=_get_stride(x),
|
| 468 |
-
stride_y_row=_get_stride(y),
|
| 469 |
-
BLOCK_SIZE=B,
|
| 470 |
-
)
|
| 471 |
-
return y
|
| 472 |
-
|
| 473 |
-
|
| 474 |
-
@torch.compiler.disable
|
| 475 |
-
def gelu_bwd_npu(g: torch.Tensor, x: torch.Tensor) -> torch.Tensor:
|
| 476 |
-
x = _ensure_inner_contiguous(x)
|
| 477 |
-
g = _ensure_inner_contiguous(g)
|
| 478 |
-
T, D = x.numel(), x.shape[-1]
|
| 479 |
-
dx = _alloc_output(x)
|
| 480 |
-
grid, B = _activation_launch_config(T, is_backward=True)
|
| 481 |
-
gelu_bwd_kernel[grid](
|
| 482 |
-
x, g, dx, T=T, D=D,
|
| 483 |
-
stride_x_row=_get_stride(x),
|
| 484 |
-
stride_dy_row=_get_stride(g),
|
| 485 |
-
stride_dx_row=_get_stride(dx),
|
| 486 |
-
BLOCK_SIZE=B,
|
| 487 |
-
)
|
| 488 |
-
return dx
|
| 489 |
-
|
| 490 |
-
|
| 491 |
-
@torch.compiler.disable
|
| 492 |
-
def sqrelu_fwd_npu(x: torch.Tensor) -> torch.Tensor:
|
| 493 |
-
x = _ensure_inner_contiguous(x)
|
| 494 |
-
T, D = x.numel(), x.shape[-1]
|
| 495 |
-
y = _alloc_output(x)
|
| 496 |
-
grid, B = _activation_launch_config(T)
|
| 497 |
-
sqrelu_fwd_kernel[grid](
|
| 498 |
-
x, y, T=T, D=D,
|
| 499 |
-
stride_x_row=_get_stride(x),
|
| 500 |
-
stride_y_row=_get_stride(y),
|
| 501 |
-
BLOCK_SIZE=B,
|
| 502 |
-
)
|
| 503 |
-
return y
|
| 504 |
-
|
| 505 |
-
|
| 506 |
-
@torch.compiler.disable
|
| 507 |
-
def sqrelu_bwd_npu(g: torch.Tensor, x: torch.Tensor) -> torch.Tensor:
|
| 508 |
-
x = _ensure_inner_contiguous(x)
|
| 509 |
-
g = _ensure_inner_contiguous(g)
|
| 510 |
-
T, D = x.numel(), x.shape[-1]
|
| 511 |
-
dx = _alloc_output(x)
|
| 512 |
-
grid, B = _activation_launch_config(T, is_backward=True)
|
| 513 |
-
sqrelu_bwd_kernel[grid](
|
| 514 |
-
x, g, dx, T=T, D=D,
|
| 515 |
-
stride_x_row=_get_stride(x),
|
| 516 |
-
stride_dy_row=_get_stride(g),
|
| 517 |
-
stride_dx_row=_get_stride(dx),
|
| 518 |
-
BLOCK_SIZE=B,
|
| 519 |
-
)
|
| 520 |
-
return dx
|
| 521 |
-
|
| 522 |
-
|
| 523 |
-
@torch.compiler.disable
|
| 524 |
-
def sigmoid_fwd_npu(x: torch.Tensor, output_contiguous: bool = False) -> torch.Tensor:
|
| 525 |
-
x = _ensure_inner_contiguous(x)
|
| 526 |
-
T, D = x.numel(), x.shape[-1]
|
| 527 |
-
y = _alloc_output(x, output_contiguous)
|
| 528 |
-
grid, B = _activation_launch_config(T)
|
| 529 |
-
sigmoid_fwd_kernel[grid](
|
| 530 |
-
x, y, T=T, D=D,
|
| 531 |
-
stride_x_row=_get_stride(x),
|
| 532 |
-
stride_y_row=_get_stride(y),
|
| 533 |
-
B=B,
|
| 534 |
-
)
|
| 535 |
-
return y
|
| 536 |
-
|
| 537 |
-
|
| 538 |
-
@torch.compiler.disable
|
| 539 |
-
def sigmoid_bwd_npu(x: torch.Tensor, dy: torch.Tensor, output_contiguous: bool = False) -> torch.Tensor:
|
| 540 |
-
x = _ensure_inner_contiguous(x)
|
| 541 |
-
dy = _ensure_inner_contiguous(dy)
|
| 542 |
-
T, D = x.numel(), x.shape[-1]
|
| 543 |
-
dx = _alloc_output(x, output_contiguous)
|
| 544 |
-
grid, B = _activation_launch_config(T, is_backward=True)
|
| 545 |
-
sigmoid_bwd_kernel[grid](
|
| 546 |
-
x, dy, dx, T=T, D=D,
|
| 547 |
-
stride_x_row=_get_stride(x),
|
| 548 |
-
stride_dy_row=_get_stride(dy),
|
| 549 |
-
stride_dx_row=_get_stride(dx),
|
| 550 |
-
B=B,
|
| 551 |
-
)
|
| 552 |
-
return dx
|
| 553 |
-
|
| 554 |
-
|
| 555 |
-
@torch.compiler.disable
|
| 556 |
-
def logsigmoid_fwd_npu(x: torch.Tensor, temperature: float = 1., output_contiguous: bool = False) -> torch.Tensor:
|
| 557 |
-
x = _ensure_inner_contiguous(x)
|
| 558 |
-
T, D = x.numel(), x.shape[-1]
|
| 559 |
-
y = _alloc_output(x, output_contiguous)
|
| 560 |
-
grid, B = _activation_launch_config(T)
|
| 561 |
-
logsigmoid_fwd_kernel[grid](
|
| 562 |
-
x=x,
|
| 563 |
-
y=y,
|
| 564 |
-
temperature=temperature,
|
| 565 |
-
T=T,
|
| 566 |
-
D=D,
|
| 567 |
-
stride_x_row=_get_stride(x),
|
| 568 |
-
stride_y_row=_get_stride(y),
|
| 569 |
-
B=B,
|
| 570 |
-
)
|
| 571 |
-
return y
|
| 572 |
-
|
| 573 |
-
|
| 574 |
-
@torch.compiler.disable
|
| 575 |
-
def logsigmoid_bwd_npu(
|
| 576 |
-
x: torch.Tensor,
|
| 577 |
-
dy: torch.Tensor,
|
| 578 |
-
temperature: float = 1.,
|
| 579 |
-
output_contiguous: bool = False,
|
| 580 |
-
) -> torch.Tensor:
|
| 581 |
-
x = _ensure_inner_contiguous(x)
|
| 582 |
-
dy = _ensure_inner_contiguous(dy)
|
| 583 |
-
T, D = x.numel(), x.shape[-1]
|
| 584 |
-
dx = _alloc_output(x, output_contiguous)
|
| 585 |
-
grid, B = _activation_launch_config(T, is_backward=True)
|
| 586 |
-
logsigmoid_bwd_kernel[grid](
|
| 587 |
-
x=x,
|
| 588 |
-
dx=dx,
|
| 589 |
-
dy=dy,
|
| 590 |
-
temperature=temperature,
|
| 591 |
-
T=T,
|
| 592 |
-
D=D,
|
| 593 |
-
stride_x_row=_get_stride(x),
|
| 594 |
-
stride_dx_row=_get_stride(dx),
|
| 595 |
-
stride_dy_row=_get_stride(dy),
|
| 596 |
-
B=B,
|
| 597 |
-
)
|
| 598 |
-
return dx
|
| 599 |
-
|
| 600 |
-
|
| 601 |
-
@torch.compiler.disable
|
| 602 |
-
def swish_fwd_npu(x: torch.Tensor, output_contiguous: bool = False) -> torch.Tensor:
|
| 603 |
-
x = _ensure_inner_contiguous(x)
|
| 604 |
-
T, D = x.numel(), x.shape[-1]
|
| 605 |
-
y = _alloc_output(x, output_contiguous)
|
| 606 |
-
grid, B = _activation_launch_config(T)
|
| 607 |
-
swish_fwd_kernel[grid](
|
| 608 |
-
x, y, T=T, D=D,
|
| 609 |
-
stride_x_row=_get_stride(x),
|
| 610 |
-
stride_y_row=_get_stride(y),
|
| 611 |
-
B=B,
|
| 612 |
-
)
|
| 613 |
-
return y
|
| 614 |
-
|
| 615 |
-
|
| 616 |
-
@torch.compiler.disable
|
| 617 |
-
def swish_bwd_npu(x: torch.Tensor, dy: torch.Tensor, output_contiguous: bool = False) -> torch.Tensor:
|
| 618 |
-
x = _ensure_inner_contiguous(x)
|
| 619 |
-
dy = _ensure_inner_contiguous(dy)
|
| 620 |
-
T, D = x.numel(), x.shape[-1]
|
| 621 |
-
dx = _alloc_output(x, output_contiguous)
|
| 622 |
-
grid, B = _activation_launch_config(T, is_backward=True)
|
| 623 |
-
swish_bwd_kernel[grid](
|
| 624 |
-
x, dy, dx, T=T, D=D,
|
| 625 |
-
stride_x_row=_get_stride(x),
|
| 626 |
-
stride_dy_row=_get_stride(dy),
|
| 627 |
-
stride_dx_row=_get_stride(dx),
|
| 628 |
-
B=B,
|
| 629 |
-
)
|
| 630 |
-
return dx
|
| 631 |
-
|
| 632 |
-
|
| 633 |
-
@torch.compiler.disable
|
| 634 |
-
def swiglu_fwd_npu(x: torch.Tensor, y: torch.Tensor, output_contiguous: bool = False) -> torch.Tensor:
|
| 635 |
-
assert x.shape == y.shape, f"swiglu_fwd: shape mismatch x={x.shape} y={y.shape}"
|
| 636 |
-
x = _ensure_inner_contiguous(x)
|
| 637 |
-
y = _ensure_inner_contiguous(y)
|
| 638 |
-
T, D = x.numel(), x.shape[-1]
|
| 639 |
-
z = _alloc_output(x, output_contiguous)
|
| 640 |
-
grid, B = _activation_launch_config(T)
|
| 641 |
-
swiglu_fwd_kernel[grid](
|
| 642 |
-
x, y, z, T=T, D=D,
|
| 643 |
-
stride_x_row=_get_stride(x),
|
| 644 |
-
stride_y_row=_get_stride(y),
|
| 645 |
-
stride_z_row=_get_stride(z),
|
| 646 |
-
B=B,
|
| 647 |
-
)
|
| 648 |
-
return z
|
| 649 |
-
|
| 650 |
-
|
| 651 |
-
@torch.compiler.disable
|
| 652 |
-
def swiglu_fwdbwd_npu(
|
| 653 |
-
x: torch.Tensor,
|
| 654 |
-
y: torch.Tensor,
|
| 655 |
-
g: torch.Tensor,
|
| 656 |
-
use_weight: bool = False,
|
| 657 |
-
output_contiguous: bool = False,
|
| 658 |
-
):
|
| 659 |
-
assert x.shape == y.shape == g.shape, f"swiglu_fwdbwd: shape mismatch x={x.shape} y={y.shape} g={g.shape}"
|
| 660 |
-
x = _ensure_inner_contiguous(x)
|
| 661 |
-
y = _ensure_inner_contiguous(y)
|
| 662 |
-
g = _ensure_inner_contiguous(g)
|
| 663 |
-
T, D = x.numel(), x.shape[-1]
|
| 664 |
-
dx = _alloc_output(x, output_contiguous)
|
| 665 |
-
dy = _alloc_output(y, output_contiguous)
|
| 666 |
-
if use_weight:
|
| 667 |
-
z = _alloc_output(x, output_contiguous)
|
| 668 |
-
else:
|
| 669 |
-
z = None
|
| 670 |
-
grid, B = _activation_launch_config(T, is_backward=True)
|
| 671 |
-
swiglu_fwdbwd_kernel[grid](
|
| 672 |
-
x, y, g, dx, dy, z, T=T, D=D,
|
| 673 |
-
stride_x_row=_get_stride(x),
|
| 674 |
-
stride_y_row=_get_stride(y),
|
| 675 |
-
stride_g_row=_get_stride(g),
|
| 676 |
-
stride_dx_row=_get_stride(dx),
|
| 677 |
-
stride_dy_row=_get_stride(dy),
|
| 678 |
-
stride_z_row=_get_stride(z) if z is not None else 0,
|
| 679 |
-
B=B,
|
| 680 |
-
)
|
| 681 |
-
if use_weight:
|
| 682 |
-
return dx, dy, z
|
| 683 |
-
return dx, dy
|
| 684 |
-
|
| 685 |
-
|
| 686 |
-
class SwiGLULinearFunctionNPU(torch.autograd.Function):
|
| 687 |
-
|
| 688 |
-
@staticmethod
|
| 689 |
-
@input_guard(no_guard_contiguous=True)
|
| 690 |
-
@autocast_custom_fwd
|
| 691 |
-
def forward(ctx, x, y, weight, bias):
|
| 692 |
-
z = swiglu_fwd_npu(x, y, output_contiguous=True)
|
| 693 |
-
out = F.linear(z, weight, bias)
|
| 694 |
-
ctx.save_for_backward(x, y, weight)
|
| 695 |
-
ctx.linear_bias_is_none = bias is None
|
| 696 |
-
return out
|
| 697 |
-
|
| 698 |
-
@staticmethod
|
| 699 |
-
@input_guard(no_guard_contiguous=True)
|
| 700 |
-
@autocast_custom_bwd
|
| 701 |
-
def backward(ctx, dout, *args):
|
| 702 |
-
x, y, weight = ctx.saved_tensors
|
| 703 |
-
dout = dout.reshape(-1, dout.shape[-1])
|
| 704 |
-
dz = F.linear(dout, weight.t()).view_as(x)
|
| 705 |
-
dx, dy, z = swiglu_fwdbwd_npu(x, y, dz, use_weight=True, output_contiguous=True)
|
| 706 |
-
z_flat = z.reshape(-1, z.shape[-1])
|
| 707 |
-
dlinear_weight = dout.t() @ z_flat
|
| 708 |
-
dlinear_bias = None if ctx.linear_bias_is_none else dout.sum(0)
|
| 709 |
-
return dx, dy, dlinear_weight, dlinear_bias
|
| 710 |
-
|
| 711 |
-
|
| 712 |
-
def swiglu_linear_npu(x, y, weight, bias):
|
| 713 |
-
return SwiGLULinearFunctionNPU.apply(x, y, weight, bias)
|
| 714 |
-
|
| 715 |
-
|
| 716 |
-
@triton.heuristics(_LINEAR_HEURISTICS_XYZ)
|
| 717 |
-
@triton.jit(do_not_specialize=['T'])
|
| 718 |
-
def powglu_fwd_kernel(
|
| 719 |
-
x, y, z,
|
| 720 |
-
stride_x_row,
|
| 721 |
-
stride_y_row,
|
| 722 |
-
stride_z_row,
|
| 723 |
-
m,
|
| 724 |
-
T,
|
| 725 |
-
D: tl.constexpr,
|
| 726 |
-
B: tl.constexpr,
|
| 727 |
-
X_LINEAR: tl.constexpr,
|
| 728 |
-
Y_LINEAR: tl.constexpr,
|
| 729 |
-
Z_LINEAR: tl.constexpr,
|
| 730 |
-
):
|
| 731 |
-
i_n = tl.program_id(0)
|
| 732 |
-
offs = i_n * B + tl.arange(0, B)
|
| 733 |
-
mask = offs < T
|
| 734 |
-
x_off = _flat_offset(offs, D, stride_x_row, X_LINEAR)
|
| 735 |
-
y_off = _flat_offset(offs, D, stride_y_row, Y_LINEAR)
|
| 736 |
-
z_off = _flat_offset(offs, D, stride_z_row, Z_LINEAR)
|
| 737 |
-
b_x = tl.load(x + x_off, mask=mask, other=0.).to(tl.float32)
|
| 738 |
-
b_y = tl.load(y + y_off, mask=mask, other=0.).to(tl.float32)
|
| 739 |
-
b_s = tl.sigmoid(b_x)
|
| 740 |
-
b_pos = b_x > 0
|
| 741 |
-
# feed only positive lanes to log/sqrt; masked lanes give x**p = 1 and are dropped by the where
|
| 742 |
-
b_xp = tl.where(b_pos, b_x, 1.0)
|
| 743 |
-
b_sqrt = tl.sqrt(b_xp)
|
| 744 |
-
b_p = m / (b_sqrt + 1.0)
|
| 745 |
-
b_pow = exp(b_p * log(b_xp))
|
| 746 |
-
b_g = tl.where(b_pos, b_pow * b_s, b_x * b_s)
|
| 747 |
-
b_z = b_g * b_y
|
| 748 |
-
tl.store(z + z_off, b_z.to(z.dtype.element_ty), mask=mask)
|
| 749 |
-
|
| 750 |
-
|
| 751 |
-
@triton.heuristics({
|
| 752 |
-
'HAS_WEIGHT': lambda args: args['z'] is not None,
|
| 753 |
-
**_LINEAR_HEURISTICS_FWDBWD,
|
| 754 |
-
})
|
| 755 |
-
@triton.jit(do_not_specialize=['T'])
|
| 756 |
-
def powglu_fwdbwd_kernel(
|
| 757 |
-
x, y, g, dx, dy, z,
|
| 758 |
-
stride_x_row,
|
| 759 |
-
stride_y_row,
|
| 760 |
-
stride_g_row,
|
| 761 |
-
stride_dx_row,
|
| 762 |
-
stride_dy_row,
|
| 763 |
-
stride_z_row,
|
| 764 |
-
m,
|
| 765 |
-
T,
|
| 766 |
-
D: tl.constexpr,
|
| 767 |
-
B: tl.constexpr,
|
| 768 |
-
HAS_WEIGHT: tl.constexpr,
|
| 769 |
-
X_LINEAR: tl.constexpr,
|
| 770 |
-
Y_LINEAR: tl.constexpr,
|
| 771 |
-
G_LINEAR: tl.constexpr,
|
| 772 |
-
DX_LINEAR: tl.constexpr,
|
| 773 |
-
DY_LINEAR: tl.constexpr,
|
| 774 |
-
Z_LINEAR: tl.constexpr,
|
| 775 |
-
):
|
| 776 |
-
i_n = tl.program_id(0)
|
| 777 |
-
offs = i_n * B + tl.arange(0, B)
|
| 778 |
-
mask = offs < T
|
| 779 |
-
x_off = _flat_offset(offs, D, stride_x_row, X_LINEAR)
|
| 780 |
-
y_off = _flat_offset(offs, D, stride_y_row, Y_LINEAR)
|
| 781 |
-
g_off = _flat_offset(offs, D, stride_g_row, G_LINEAR)
|
| 782 |
-
dx_off = _flat_offset(offs, D, stride_dx_row, DX_LINEAR)
|
| 783 |
-
dy_off = _flat_offset(offs, D, stride_dy_row, DY_LINEAR)
|
| 784 |
-
b_x = tl.load(x + x_off, mask=mask, other=0.).to(tl.float32)
|
| 785 |
-
b_y = tl.load(y + y_off, mask=mask, other=0.).to(tl.float32)
|
| 786 |
-
b_g = tl.load(g + g_off, mask=mask, other=0.).to(tl.float32)
|
| 787 |
-
|
| 788 |
-
b_s = tl.sigmoid(b_x)
|
| 789 |
-
b_pos = b_x > 0
|
| 790 |
-
b_xp = tl.where(b_pos, b_x, 1.0)
|
| 791 |
-
b_sqrt = tl.sqrt(b_xp)
|
| 792 |
-
b_ln = log(b_xp)
|
| 793 |
-
b_p = m / (b_sqrt + 1.0)
|
| 794 |
-
b_pow = exp(b_p * b_ln)
|
| 795 |
-
|
| 796 |
-
b_gate_pos = b_pow * b_s
|
| 797 |
-
# d/dx of the exponent term: p' = -m / (2*sqrt(x)*(sqrt(x)+1)**2)
|
| 798 |
-
b_pprime = -m / (2.0 * b_sqrt * (b_sqrt + 1.0) * (b_sqrt + 1.0))
|
| 799 |
-
b_dgate_pos = b_gate_pos * (b_pprime * b_ln + b_p / b_xp + 1.0 - b_s)
|
| 800 |
-
b_gate_neg = b_x * b_s
|
| 801 |
-
b_dgate_neg = b_s * (1.0 + b_x * (1.0 - b_s))
|
| 802 |
-
|
| 803 |
-
b_gate = tl.where(b_pos, b_gate_pos, b_gate_neg)
|
| 804 |
-
b_dgate = tl.where(b_pos, b_dgate_pos, b_dgate_neg)
|
| 805 |
-
|
| 806 |
-
b_dx = b_g * b_y * b_dgate
|
| 807 |
-
b_dy = b_g * b_gate
|
| 808 |
-
|
| 809 |
-
tl.store(dx + dx_off, b_dx.to(dx.dtype.element_ty), mask=mask)
|
| 810 |
-
tl.store(dy + dy_off, b_dy.to(dy.dtype.element_ty), mask=mask)
|
| 811 |
-
if HAS_WEIGHT:
|
| 812 |
-
b_z = b_gate * b_y
|
| 813 |
-
z_off = _flat_offset(offs, D, stride_z_row, Z_LINEAR)
|
| 814 |
-
tl.store(z + z_off, b_z.to(z.dtype.element_ty), mask=mask)
|
| 815 |
-
|
| 816 |
-
|
| 817 |
-
# Peak fp32 temporaries: sigmoid, sqrt, log, exp, pow, gate, output.
|
| 818 |
-
_POWGLU_FWD_MEM_MULT = 8.0
|
| 819 |
-
_POWGLU_BWD_MEM_MULT = 10.0
|
| 820 |
-
|
| 821 |
-
|
| 822 |
-
@torch.compiler.disable
|
| 823 |
-
def powglu_fwd_npu(x: torch.Tensor, y: torch.Tensor, power: float = 3.0, output_contiguous: bool = False) -> torch.Tensor:
|
| 824 |
-
assert x.shape == y.shape, f"powglu_fwd: shape mismatch x={x.shape} y={y.shape}"
|
| 825 |
-
x = _ensure_inner_contiguous(x)
|
| 826 |
-
y = _ensure_inner_contiguous(y)
|
| 827 |
-
T, D = x.numel(), x.shape[-1]
|
| 828 |
-
z = _alloc_output(x, output_contiguous)
|
| 829 |
-
grid, B = _activation_launch_config(T, memory_multiplier=_POWGLU_FWD_MEM_MULT)
|
| 830 |
-
powglu_fwd_kernel[grid](
|
| 831 |
-
x=x,
|
| 832 |
-
y=y,
|
| 833 |
-
z=z,
|
| 834 |
-
stride_x_row=_get_stride(x),
|
| 835 |
-
stride_y_row=_get_stride(y),
|
| 836 |
-
stride_z_row=_get_stride(z),
|
| 837 |
-
m=power,
|
| 838 |
-
T=T,
|
| 839 |
-
D=D,
|
| 840 |
-
B=B,
|
| 841 |
-
)
|
| 842 |
-
return z
|
| 843 |
-
|
| 844 |
-
|
| 845 |
-
@torch.compiler.disable
|
| 846 |
-
def powglu_fwdbwd_npu(
|
| 847 |
-
x: torch.Tensor,
|
| 848 |
-
y: torch.Tensor,
|
| 849 |
-
g: torch.Tensor,
|
| 850 |
-
power: float = 3.0,
|
| 851 |
-
use_weight: bool = False,
|
| 852 |
-
output_contiguous: bool = False,
|
| 853 |
-
):
|
| 854 |
-
assert x.shape == y.shape == g.shape, f"powglu_fwdbwd: shape mismatch x={x.shape} y={y.shape} g={g.shape}"
|
| 855 |
-
x = _ensure_inner_contiguous(x)
|
| 856 |
-
y = _ensure_inner_contiguous(y)
|
| 857 |
-
g = _ensure_inner_contiguous(g)
|
| 858 |
-
T, D = x.numel(), x.shape[-1]
|
| 859 |
-
dx = _alloc_output(x, output_contiguous)
|
| 860 |
-
dy = _alloc_output(y, output_contiguous)
|
| 861 |
-
if use_weight:
|
| 862 |
-
z = _alloc_output(x, output_contiguous)
|
| 863 |
-
else:
|
| 864 |
-
z = None
|
| 865 |
-
grid, B = _activation_launch_config(T, is_backward=True, memory_multiplier=_POWGLU_BWD_MEM_MULT)
|
| 866 |
-
powglu_fwdbwd_kernel[grid](
|
| 867 |
-
x=x,
|
| 868 |
-
y=y,
|
| 869 |
-
g=g,
|
| 870 |
-
dx=dx,
|
| 871 |
-
dy=dy,
|
| 872 |
-
z=z,
|
| 873 |
-
stride_x_row=_get_stride(x),
|
| 874 |
-
stride_y_row=_get_stride(y),
|
| 875 |
-
stride_g_row=_get_stride(g),
|
| 876 |
-
stride_dx_row=_get_stride(dx),
|
| 877 |
-
stride_dy_row=_get_stride(dy),
|
| 878 |
-
stride_z_row=_get_stride(z) if z is not None else 0,
|
| 879 |
-
m=power,
|
| 880 |
-
T=T,
|
| 881 |
-
D=D,
|
| 882 |
-
B=B,
|
| 883 |
-
)
|
| 884 |
-
if use_weight:
|
| 885 |
-
return dx, dy, z
|
| 886 |
-
return dx, dy
|
| 887 |
-
|
| 888 |
-
|
| 889 |
-
class PowGLULinearFunctionNPU(torch.autograd.Function):
|
| 890 |
-
r"""
|
| 891 |
-
Power-Gated Linear Unit (PowGLU) function followed by a linear transformation.
|
| 892 |
-
|
| 893 |
-
.. math::
|
| 894 |
-
\text{PowGLULinear}(x, y, W, b) = (g(x) * y) W + b
|
| 895 |
-
|
| 896 |
-
This simple wrap discards the intermediate results of PowGLU(x, y) to save memory.
|
| 897 |
-
"""
|
| 898 |
-
|
| 899 |
-
@staticmethod
|
| 900 |
-
@input_guard(no_guard_contiguous=True)
|
| 901 |
-
@autocast_custom_fwd
|
| 902 |
-
def forward(ctx, x, y, weight, bias, power):
|
| 903 |
-
z = powglu_fwd_npu(x, y, power, output_contiguous=True)
|
| 904 |
-
out = F.linear(z, weight, bias)
|
| 905 |
-
ctx.save_for_backward(x, y, weight)
|
| 906 |
-
ctx.linear_bias_is_none = bias is None
|
| 907 |
-
ctx.power = power
|
| 908 |
-
return out
|
| 909 |
-
|
| 910 |
-
@staticmethod
|
| 911 |
-
@input_guard(no_guard_contiguous=True)
|
| 912 |
-
@autocast_custom_bwd
|
| 913 |
-
def backward(ctx, dout, *args):
|
| 914 |
-
x, y, weight = ctx.saved_tensors
|
| 915 |
-
dout = dout.reshape(-1, dout.shape[-1])
|
| 916 |
-
dz = F.linear(dout, weight.t()).view_as(x)
|
| 917 |
-
dx, dy, z = powglu_fwdbwd_npu(x, y, dz, ctx.power, use_weight=True, output_contiguous=True)
|
| 918 |
-
z_flat = z.reshape(-1, z.shape[-1])
|
| 919 |
-
dlinear_weight = dout.t() @ z_flat
|
| 920 |
-
dlinear_bias = None if ctx.linear_bias_is_none else dout.sum(0)
|
| 921 |
-
return dx, dy, dlinear_weight, dlinear_bias, None
|
| 922 |
-
|
| 923 |
-
|
| 924 |
-
def powglu_linear_npu(
|
| 925 |
-
x: torch.Tensor,
|
| 926 |
-
y: torch.Tensor,
|
| 927 |
-
weight: torch.Tensor,
|
| 928 |
-
bias: torch.Tensor,
|
| 929 |
-
power: float = 3.0,
|
| 930 |
-
) -> torch.Tensor:
|
| 931 |
-
return PowGLULinearFunctionNPU.apply(x, y, weight, bias, power)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
build/torch-cuda/modules/backends/triton_ascend/causal_conv1d.py
DELETED
|
@@ -1,1175 +0,0 @@
|
|
| 1 |
-
# Copyright (c) 2023-2026, Songlin Yang, Yu Zhang, Zhiyuan Li
|
| 2 |
-
#
|
| 3 |
-
# This source code is licensed under the MIT license found in the
|
| 4 |
-
# LICENSE file in the root directory of this source tree.
|
| 5 |
-
# For a list of all contributors, visit:
|
| 6 |
-
# https://github.com/fla-org/flash-linear-attention/graphs/contributors
|
| 7 |
-
|
| 8 |
-
"""Causal 1D convolution kernels adapted for triton-ascend on Huawei NPU."""
|
| 9 |
-
|
| 10 |
-
import torch
|
| 11 |
-
import triton
|
| 12 |
-
import triton.language as tl
|
| 13 |
-
from einops import rearrange
|
| 14 |
-
|
| 15 |
-
from ....ops.utils import prepare_chunk_indices
|
| 16 |
-
from ....utils import input_guard
|
| 17 |
-
|
| 18 |
-
STATIC_WARPS = 2
|
| 19 |
-
# Ascend Triton rejects grids whose product exceeds 65535 (see fla/modules/token_shift.py).
|
| 20 |
-
_NPU_MAX_TRITON_GRID = 65535
|
| 21 |
-
_ELEM_BLOCK = 2048
|
| 22 |
-
|
| 23 |
-
|
| 24 |
-
def _elementwise_launch_iters(numel: int):
|
| 25 |
-
n_blocks = triton.cdiv(numel, _ELEM_BLOCK)
|
| 26 |
-
for block_off in range(0, n_blocks, _NPU_MAX_TRITON_GRID):
|
| 27 |
-
yield min(_NPU_MAX_TRITON_GRID, n_blocks - block_off), block_off * _ELEM_BLOCK
|
| 28 |
-
|
| 29 |
-
|
| 30 |
-
def _npu_chunk_size(T: int, BT: int) -> int:
|
| 31 |
-
BT = min(max(BT, 1), 64)
|
| 32 |
-
if BT not in (1, 2, 4, 8, 16, 32, 64):
|
| 33 |
-
BT = triton.next_power_of_2(BT)
|
| 34 |
-
# Ascend compiler requires power-of-2 BT; pad with mask when BT > T.
|
| 35 |
-
if T not in (1, 2, 4, 8, 16, 32, 64):
|
| 36 |
-
BT = min(triton.next_power_of_2(T), 64)
|
| 37 |
-
else:
|
| 38 |
-
BT = min(BT, T, 64)
|
| 39 |
-
return BT
|
| 40 |
-
|
| 41 |
-
|
| 42 |
-
def _clamp_bd_for_grid(B: int, NT: int, D: int, BD: int) -> int:
|
| 43 |
-
while triton.cdiv(D, BD) * NT * B > _NPU_MAX_TRITON_GRID and BD < 64:
|
| 44 |
-
BD *= 2
|
| 45 |
-
return BD
|
| 46 |
-
|
| 47 |
-
|
| 48 |
-
def _npu_max_axis_chunks(grid_dim0: int, batch: int = 1) -> int:
|
| 49 |
-
denom = grid_dim0 * batch
|
| 50 |
-
if denom > _NPU_MAX_TRITON_GRID:
|
| 51 |
-
raise RuntimeError(
|
| 52 |
-
f'Ascend Triton grid dim0*batch={denom} exceeds {_NPU_MAX_TRITON_GRID}',
|
| 53 |
-
)
|
| 54 |
-
return max(1, _NPU_MAX_TRITON_GRID // max(denom, 1))
|
| 55 |
-
|
| 56 |
-
|
| 57 |
-
def _npu_tile_config(
|
| 58 |
-
T: int,
|
| 59 |
-
BT: int,
|
| 60 |
-
D: int,
|
| 61 |
-
dtype: torch.dtype,
|
| 62 |
-
initial_state: torch.Tensor | None,
|
| 63 |
-
) -> tuple[int, int, int]:
|
| 64 |
-
BT = _npu_chunk_size(T, BT)
|
| 65 |
-
BD = 16
|
| 66 |
-
if D >= 8192:
|
| 67 |
-
BD = 8
|
| 68 |
-
BT = min(BT, 8)
|
| 69 |
-
elif D >= 1024:
|
| 70 |
-
# BD=4 overflows Ascend UB on large-D forward; cap BT to limit NT.
|
| 71 |
-
BD = 8
|
| 72 |
-
BT = min(BT, 32)
|
| 73 |
-
elif D >= 512:
|
| 74 |
-
BD = 8
|
| 75 |
-
if dtype == torch.float16 and initial_state is not None:
|
| 76 |
-
BD = min(BD, 8)
|
| 77 |
-
if dtype == torch.bfloat16 and T <= 16:
|
| 78 |
-
BD = 8
|
| 79 |
-
return BD, BT, STATIC_WARPS
|
| 80 |
-
|
| 81 |
-
|
| 82 |
-
def _npu_bwd_tile_config(
|
| 83 |
-
T: int,
|
| 84 |
-
BT: int,
|
| 85 |
-
D: int,
|
| 86 |
-
dtype: torch.dtype,
|
| 87 |
-
initial_state: torch.Tensor | None,
|
| 88 |
-
) -> tuple[int, int, int]:
|
| 89 |
-
BT = _npu_chunk_size(T, BT)
|
| 90 |
-
BD = 16
|
| 91 |
-
if initial_state is not None:
|
| 92 |
-
BD = min(BD, 8)
|
| 93 |
-
BT = min(BT, 32)
|
| 94 |
-
if D >= 2048:
|
| 95 |
-
BD = 8
|
| 96 |
-
BT = min(BT, 8)
|
| 97 |
-
elif D >= 1024:
|
| 98 |
-
BD = 8
|
| 99 |
-
BT = min(BT, 16)
|
| 100 |
-
elif D >= 512:
|
| 101 |
-
BD = 8
|
| 102 |
-
BT = min(BT, 32)
|
| 103 |
-
if dtype == torch.bfloat16 and T <= 16:
|
| 104 |
-
BD = 8
|
| 105 |
-
BT = 32
|
| 106 |
-
return BD, BT, STATIC_WARPS
|
| 107 |
-
|
| 108 |
-
|
| 109 |
-
@triton.heuristics({
|
| 110 |
-
'HAS_WEIGHT': lambda args: args['weight'] is not None,
|
| 111 |
-
'HAS_BIAS': lambda args: args['bias'] is not None,
|
| 112 |
-
'USE_INITIAL_STATE': lambda args: args['initial_state'] is not None,
|
| 113 |
-
'IS_VARLEN': lambda args: args['cu_seqlens'] is not None,
|
| 114 |
-
})
|
| 115 |
-
@triton.jit
|
| 116 |
-
def causal_conv1d_fwd_kernel(
|
| 117 |
-
x,
|
| 118 |
-
y,
|
| 119 |
-
weight,
|
| 120 |
-
bias,
|
| 121 |
-
cu_seqlens,
|
| 122 |
-
initial_state,
|
| 123 |
-
chunk_indices,
|
| 124 |
-
B,
|
| 125 |
-
T,
|
| 126 |
-
stride_x_n,
|
| 127 |
-
stride_x_t,
|
| 128 |
-
stride_x_d,
|
| 129 |
-
stride_y_n,
|
| 130 |
-
stride_y_t,
|
| 131 |
-
stride_y_d,
|
| 132 |
-
D: tl.constexpr,
|
| 133 |
-
W: tl.constexpr,
|
| 134 |
-
BT: tl.constexpr,
|
| 135 |
-
BW: tl.constexpr,
|
| 136 |
-
BD: tl.constexpr,
|
| 137 |
-
HAS_WEIGHT: tl.constexpr,
|
| 138 |
-
HAS_BIAS: tl.constexpr,
|
| 139 |
-
USE_INITIAL_STATE: tl.constexpr,
|
| 140 |
-
IS_VARLEN: tl.constexpr,
|
| 141 |
-
CHUNK_OFFSET: tl.constexpr,
|
| 142 |
-
):
|
| 143 |
-
i_d, i_t, i_b = tl.program_id(0), tl.program_id(1), tl.program_id(2)
|
| 144 |
-
|
| 145 |
-
if IS_VARLEN:
|
| 146 |
-
i_n, i_t = tl.load(chunk_indices + i_t * 2).to(tl.int32), tl.load(chunk_indices + i_t * 2 + 1).to(tl.int32)
|
| 147 |
-
bos, eos = tl.load(cu_seqlens + i_n).to(tl.int64), tl.load(cu_seqlens + i_n + 1).to(tl.int64)
|
| 148 |
-
T = eos - bos
|
| 149 |
-
p_x = x + bos * stride_x_t
|
| 150 |
-
p_y = y + bos * stride_y_t
|
| 151 |
-
else:
|
| 152 |
-
i_n = i_b
|
| 153 |
-
i_t = i_t + CHUNK_OFFSET
|
| 154 |
-
bos = (i_b * T).to(tl.int64)
|
| 155 |
-
p_x = x + tl.cast(i_b, tl.int64) * stride_x_n
|
| 156 |
-
p_y = y + tl.cast(i_b, tl.int64) * stride_y_n
|
| 157 |
-
|
| 158 |
-
o_d = i_d * BD + tl.arange(0, BD)
|
| 159 |
-
o_w = tl.arange(0, BW) + W - BW
|
| 160 |
-
m_d = o_d < D
|
| 161 |
-
m_w = o_w >= 0
|
| 162 |
-
|
| 163 |
-
if HAS_WEIGHT:
|
| 164 |
-
b_w = tl.load(weight + o_d[:, None] * W + o_w, mask=m_d[:, None] & m_w, other=0).to(tl.float32)
|
| 165 |
-
|
| 166 |
-
o_t = i_t * BT + tl.arange(0, BT)
|
| 167 |
-
m_t = (o_t >= 0) & (o_t < T)
|
| 168 |
-
b_y = tl.zeros((BT, BD), dtype=tl.float32)
|
| 169 |
-
|
| 170 |
-
for i_w in tl.static_range(-W + 1, 1):
|
| 171 |
-
o_x = o_t + i_w
|
| 172 |
-
m_x = ((o_x >= 0) & (o_x < T))[:, None] & m_d[None, :]
|
| 173 |
-
b_yi = tl.load(
|
| 174 |
-
p_x + o_x[:, None] * stride_x_t + o_d[None, :] * stride_x_d,
|
| 175 |
-
mask=m_x,
|
| 176 |
-
other=0,
|
| 177 |
-
).to(tl.float32)
|
| 178 |
-
|
| 179 |
-
if USE_INITIAL_STATE:
|
| 180 |
-
m_c = ((o_x + W >= 0) & (o_x < 0))[:, None] & m_d[None, :]
|
| 181 |
-
b_yi += tl.load(
|
| 182 |
-
initial_state + i_n * D * W + o_d[None, :] * W + (o_x + W)[:, None],
|
| 183 |
-
mask=m_c,
|
| 184 |
-
other=0,
|
| 185 |
-
).to(tl.float32)
|
| 186 |
-
|
| 187 |
-
if HAS_WEIGHT:
|
| 188 |
-
b_yi = b_yi * tl.sum(b_w * (o_w == (i_w + W - 1)), 1)[None, :]
|
| 189 |
-
b_y += b_yi
|
| 190 |
-
|
| 191 |
-
if HAS_BIAS:
|
| 192 |
-
b_y += tl.load(bias + o_d, mask=m_d).to(tl.float32)[None, :]
|
| 193 |
-
|
| 194 |
-
tl.store(
|
| 195 |
-
p_y + o_t[:, None] * stride_y_t + o_d[None, :] * stride_y_d,
|
| 196 |
-
tl.cast(b_y, dtype=y.dtype.element_ty, fp_downcast_rounding='rtne'),
|
| 197 |
-
mask=m_t[:, None] & m_d[None, :],
|
| 198 |
-
)
|
| 199 |
-
|
| 200 |
-
|
| 201 |
-
@triton.jit
|
| 202 |
-
def _silu_kernel(
|
| 203 |
-
x_ptr,
|
| 204 |
-
y_ptr,
|
| 205 |
-
n_elements,
|
| 206 |
-
ELEM_OFFSET: tl.constexpr,
|
| 207 |
-
BLOCK: tl.constexpr,
|
| 208 |
-
):
|
| 209 |
-
pid = tl.program_id(0)
|
| 210 |
-
offs = pid * BLOCK + tl.arange(0, BLOCK) + ELEM_OFFSET
|
| 211 |
-
mask = offs < n_elements
|
| 212 |
-
x = tl.load(x_ptr + offs, mask=mask, other=0.).to(tl.float32)
|
| 213 |
-
y = x * tl.sigmoid(x)
|
| 214 |
-
tl.store(y_ptr + offs, y.to(y_ptr.dtype.element_ty), mask=mask)
|
| 215 |
-
|
| 216 |
-
|
| 217 |
-
@triton.jit
|
| 218 |
-
def _add_kernel(
|
| 219 |
-
a_ptr,
|
| 220 |
-
b_ptr,
|
| 221 |
-
out_ptr,
|
| 222 |
-
n_elements,
|
| 223 |
-
ELEM_OFFSET: tl.constexpr,
|
| 224 |
-
BLOCK: tl.constexpr,
|
| 225 |
-
):
|
| 226 |
-
pid = tl.program_id(0)
|
| 227 |
-
offs = pid * BLOCK + tl.arange(0, BLOCK) + ELEM_OFFSET
|
| 228 |
-
mask = offs < n_elements
|
| 229 |
-
a = tl.load(a_ptr + offs, mask=mask, other=0.).to(tl.float32)
|
| 230 |
-
b = tl.load(b_ptr + offs, mask=mask, other=0.).to(tl.float32)
|
| 231 |
-
tl.store(out_ptr + offs, (a + b).to(out_ptr.dtype.element_ty), mask=mask)
|
| 232 |
-
|
| 233 |
-
|
| 234 |
-
def _launch_silu(y: torch.Tensor) -> torch.Tensor:
|
| 235 |
-
y = y.contiguous()
|
| 236 |
-
out = torch.zeros_like(y)
|
| 237 |
-
n = y.numel()
|
| 238 |
-
for grid, elem_off in _elementwise_launch_iters(n):
|
| 239 |
-
_silu_kernel[(grid,)](
|
| 240 |
-
y, out, n,
|
| 241 |
-
ELEM_OFFSET=elem_off,
|
| 242 |
-
BLOCK=_ELEM_BLOCK,
|
| 243 |
-
num_warps=STATIC_WARPS,
|
| 244 |
-
)
|
| 245 |
-
return out
|
| 246 |
-
|
| 247 |
-
|
| 248 |
-
def _launch_add(a: torch.Tensor, b: torch.Tensor) -> torch.Tensor:
|
| 249 |
-
a = a.contiguous()
|
| 250 |
-
b = b.contiguous()
|
| 251 |
-
out = torch.zeros_like(a)
|
| 252 |
-
n = a.numel()
|
| 253 |
-
for grid, elem_off in _elementwise_launch_iters(n):
|
| 254 |
-
_add_kernel[(grid,)](
|
| 255 |
-
a, b, out, n,
|
| 256 |
-
ELEM_OFFSET=elem_off,
|
| 257 |
-
BLOCK=_ELEM_BLOCK,
|
| 258 |
-
num_warps=STATIC_WARPS,
|
| 259 |
-
)
|
| 260 |
-
return out
|
| 261 |
-
|
| 262 |
-
|
| 263 |
-
@triton.jit
|
| 264 |
-
def _silu_bwd_kernel(
|
| 265 |
-
y_ptr,
|
| 266 |
-
dy_ptr,
|
| 267 |
-
out_ptr,
|
| 268 |
-
stride_y_n,
|
| 269 |
-
stride_y_t,
|
| 270 |
-
stride_y_d,
|
| 271 |
-
stride_dy_n,
|
| 272 |
-
stride_dy_t,
|
| 273 |
-
stride_dy_d,
|
| 274 |
-
stride_out_n,
|
| 275 |
-
stride_out_t,
|
| 276 |
-
stride_out_d,
|
| 277 |
-
B,
|
| 278 |
-
T,
|
| 279 |
-
D,
|
| 280 |
-
ELEM_OFFSET: tl.constexpr,
|
| 281 |
-
BLOCK: tl.constexpr,
|
| 282 |
-
):
|
| 283 |
-
pid = tl.program_id(0)
|
| 284 |
-
offs = pid * BLOCK + tl.arange(0, BLOCK) + ELEM_OFFSET
|
| 285 |
-
n_elements = B * T * D
|
| 286 |
-
mask = offs < n_elements
|
| 287 |
-
rem = offs % D
|
| 288 |
-
d = rem
|
| 289 |
-
rem = (offs - d) // D
|
| 290 |
-
t = rem % T
|
| 291 |
-
b = rem // T
|
| 292 |
-
y_off = b * stride_y_n + t * stride_y_t + d * stride_y_d
|
| 293 |
-
dy_off = b * stride_dy_n + t * stride_dy_t + d * stride_dy_d
|
| 294 |
-
out_off = b * stride_out_n + t * stride_out_t + d * stride_out_d
|
| 295 |
-
y = tl.load(y_ptr + y_off, mask=mask, other=0.).to(tl.float32)
|
| 296 |
-
dy = tl.load(dy_ptr + dy_off, mask=mask, other=0.).to(tl.float32)
|
| 297 |
-
s = tl.sigmoid(y)
|
| 298 |
-
out = dy * s * (1.0 + y * (1.0 - s))
|
| 299 |
-
tl.store(out_ptr + out_off, out.to(out_ptr.dtype.element_ty), mask=mask)
|
| 300 |
-
|
| 301 |
-
|
| 302 |
-
def _launch_silu_bwd(y_pre: torch.Tensor, dy: torch.Tensor) -> torch.Tensor:
|
| 303 |
-
out = torch.zeros_like(dy, memory_format=torch.contiguous_format)
|
| 304 |
-
B, T, D = dy.shape
|
| 305 |
-
n = B * T * D
|
| 306 |
-
sy_n, sy_t, sy_d = y_pre.stride()
|
| 307 |
-
sdy_n, sdy_t, sdy_d = dy.stride()
|
| 308 |
-
so_n, so_t, so_d = out.stride()
|
| 309 |
-
for grid, elem_off in _elementwise_launch_iters(n):
|
| 310 |
-
_silu_bwd_kernel[(grid,)](
|
| 311 |
-
y_pre, dy, out,
|
| 312 |
-
sy_n, sy_t, sy_d,
|
| 313 |
-
sdy_n, sdy_t, sdy_d,
|
| 314 |
-
so_n, so_t, so_d,
|
| 315 |
-
B, T, D,
|
| 316 |
-
ELEM_OFFSET=elem_off,
|
| 317 |
-
BLOCK=_ELEM_BLOCK,
|
| 318 |
-
num_warps=STATIC_WARPS,
|
| 319 |
-
)
|
| 320 |
-
return out
|
| 321 |
-
|
| 322 |
-
|
| 323 |
-
def _postprocess_fwd(
|
| 324 |
-
y: torch.Tensor,
|
| 325 |
-
residual: torch.Tensor | None,
|
| 326 |
-
activation: str | None,
|
| 327 |
-
) -> torch.Tensor:
|
| 328 |
-
if activation in ('swish', 'silu'):
|
| 329 |
-
y = _launch_silu(y)
|
| 330 |
-
if residual is not None:
|
| 331 |
-
if residual.stride() != y.stride():
|
| 332 |
-
residual = residual.contiguous()
|
| 333 |
-
y = _launch_add(y, residual)
|
| 334 |
-
return y
|
| 335 |
-
|
| 336 |
-
|
| 337 |
-
def _use_seq_bwd(
|
| 338 |
-
T: int,
|
| 339 |
-
dtype: torch.dtype,
|
| 340 |
-
initial_state: torch.Tensor | None,
|
| 341 |
-
dht: torch.Tensor | None,
|
| 342 |
-
cu_seqlens: torch.Tensor | None,
|
| 343 |
-
) -> bool:
|
| 344 |
-
return (
|
| 345 |
-
cu_seqlens is None
|
| 346 |
-
and initial_state is None
|
| 347 |
-
and dht is None
|
| 348 |
-
and dtype == torch.bfloat16
|
| 349 |
-
and T <= 16
|
| 350 |
-
)
|
| 351 |
-
|
| 352 |
-
|
| 353 |
-
@triton.heuristics({
|
| 354 |
-
'HAS_WEIGHT': lambda args: args['dw'] is not None,
|
| 355 |
-
'HAS_BIAS': lambda args: args['db'] is not None,
|
| 356 |
-
})
|
| 357 |
-
@triton.jit
|
| 358 |
-
def causal_conv1d_bwd_seq_kernel(
|
| 359 |
-
x,
|
| 360 |
-
weight,
|
| 361 |
-
dy,
|
| 362 |
-
dx,
|
| 363 |
-
dw,
|
| 364 |
-
db,
|
| 365 |
-
stride_x_n,
|
| 366 |
-
stride_x_t,
|
| 367 |
-
stride_x_d,
|
| 368 |
-
stride_dx_n,
|
| 369 |
-
stride_dx_t,
|
| 370 |
-
stride_dx_d,
|
| 371 |
-
stride_dy_n,
|
| 372 |
-
stride_dy_t,
|
| 373 |
-
stride_dy_d,
|
| 374 |
-
B,
|
| 375 |
-
TC: tl.constexpr,
|
| 376 |
-
D: tl.constexpr,
|
| 377 |
-
W: tl.constexpr,
|
| 378 |
-
HAS_WEIGHT: tl.constexpr,
|
| 379 |
-
HAS_BIAS: tl.constexpr,
|
| 380 |
-
BLOCK: tl.constexpr,
|
| 381 |
-
):
|
| 382 |
-
pid = tl.program_id(0)
|
| 383 |
-
offs = pid * BLOCK + tl.arange(0, BLOCK)
|
| 384 |
-
n_elements = B * TC * D
|
| 385 |
-
mask = offs < n_elements
|
| 386 |
-
d = offs % D
|
| 387 |
-
tmp = offs // D
|
| 388 |
-
t = tmp % TC
|
| 389 |
-
b = tmp // TC
|
| 390 |
-
|
| 391 |
-
b_dx = tl.zeros((BLOCK,), dtype=tl.float32)
|
| 392 |
-
for i_w in tl.static_range(0, W):
|
| 393 |
-
t_dy = t + i_w
|
| 394 |
-
dy_off = b * stride_dy_n + t_dy * stride_dy_t + d * stride_dy_d
|
| 395 |
-
b_dy = tl.load(dy + dy_off, mask=mask & (t_dy < TC), other=0.).to(tl.float32)
|
| 396 |
-
if HAS_WEIGHT:
|
| 397 |
-
w_idx = W - i_w - 1
|
| 398 |
-
b_w = tl.load(weight + d * W + w_idx, mask=mask, other=0.).to(tl.float32)
|
| 399 |
-
b_dx += b_dy * b_w
|
| 400 |
-
else:
|
| 401 |
-
b_dx += b_dy
|
| 402 |
-
|
| 403 |
-
dx_off = b * stride_dx_n + t * stride_dx_t + d * stride_dx_d
|
| 404 |
-
tl.store(dx + dx_off, b_dx.to(dx.dtype.element_ty), mask=mask)
|
| 405 |
-
|
| 406 |
-
if HAS_WEIGHT:
|
| 407 |
-
x_off = b * stride_x_n + t * stride_x_t + d * stride_x_d
|
| 408 |
-
b_x = tl.load(x + x_off, mask=mask, other=0.).to(tl.float32)
|
| 409 |
-
i_tg = b * TC + t
|
| 410 |
-
for i_w in tl.static_range(0, W):
|
| 411 |
-
t_dy = t + i_w
|
| 412 |
-
dy_off = b * stride_dy_n + t_dy * stride_dy_t + d * stride_dy_d
|
| 413 |
-
b_dy = tl.load(dy + dy_off, mask=mask & (t_dy < TC), other=0.).to(tl.float32)
|
| 414 |
-
w_idx = W - i_w - 1
|
| 415 |
-
tl.store(
|
| 416 |
-
dw + (i_tg * D + d) * W + w_idx,
|
| 417 |
-
(b_dy * b_x).to(dw.dtype.element_ty),
|
| 418 |
-
mask=mask,
|
| 419 |
-
)
|
| 420 |
-
|
| 421 |
-
if HAS_BIAS:
|
| 422 |
-
i_tg = b * TC + t
|
| 423 |
-
dy_off = b * stride_dy_n + t * stride_dy_t + d * stride_dy_d
|
| 424 |
-
b_dy0 = tl.load(dy + dy_off, mask=mask, other=0.)
|
| 425 |
-
tl.store(db + i_tg * D + d, b_dy0.to(db.dtype.element_ty), mask=mask)
|
| 426 |
-
|
| 427 |
-
|
| 428 |
-
@triton.heuristics({
|
| 429 |
-
'HAS_WEIGHT': lambda args: args['dw'] is not None,
|
| 430 |
-
'HAS_BIAS': lambda args: args['db'] is not None,
|
| 431 |
-
'USE_INITIAL_STATE': lambda args: args['initial_state'] is not None,
|
| 432 |
-
'USE_FINAL_STATE': lambda args: args['dht'] is not None,
|
| 433 |
-
'IS_VARLEN': lambda args: args['cu_seqlens'] is not None,
|
| 434 |
-
})
|
| 435 |
-
@triton.jit
|
| 436 |
-
def causal_conv1d_bwd_kernel(
|
| 437 |
-
x,
|
| 438 |
-
weight,
|
| 439 |
-
initial_state,
|
| 440 |
-
dht,
|
| 441 |
-
dy,
|
| 442 |
-
dx,
|
| 443 |
-
dw,
|
| 444 |
-
db,
|
| 445 |
-
cu_seqlens,
|
| 446 |
-
chunk_indices,
|
| 447 |
-
B,
|
| 448 |
-
T,
|
| 449 |
-
stride_x_n,
|
| 450 |
-
stride_x_t,
|
| 451 |
-
stride_x_d,
|
| 452 |
-
stride_dx_n,
|
| 453 |
-
stride_dx_t,
|
| 454 |
-
stride_dx_d,
|
| 455 |
-
stride_dy_n,
|
| 456 |
-
stride_dy_t,
|
| 457 |
-
stride_dy_d,
|
| 458 |
-
D: tl.constexpr,
|
| 459 |
-
W: tl.constexpr,
|
| 460 |
-
BT: tl.constexpr,
|
| 461 |
-
BW: tl.constexpr,
|
| 462 |
-
BD: tl.constexpr,
|
| 463 |
-
HAS_WEIGHT: tl.constexpr,
|
| 464 |
-
HAS_BIAS: tl.constexpr,
|
| 465 |
-
USE_INITIAL_STATE: tl.constexpr,
|
| 466 |
-
USE_FINAL_STATE: tl.constexpr,
|
| 467 |
-
IS_VARLEN: tl.constexpr,
|
| 468 |
-
CHUNK_OFFSET: tl.constexpr,
|
| 469 |
-
NT: tl.constexpr,
|
| 470 |
-
):
|
| 471 |
-
i_d, i_t, i_b = tl.program_id(0), tl.program_id(1), tl.program_id(2)
|
| 472 |
-
if IS_VARLEN:
|
| 473 |
-
i_tg = i_t
|
| 474 |
-
i_n, i_t = tl.load(chunk_indices + i_t * 2).to(tl.int32), tl.load(chunk_indices + i_t * 2 + 1).to(tl.int32)
|
| 475 |
-
bos, eos = tl.load(cu_seqlens + i_n).to(tl.int64), tl.load(cu_seqlens + i_n + 1).to(tl.int64)
|
| 476 |
-
T = eos - bos
|
| 477 |
-
p_x = x + bos * stride_x_t
|
| 478 |
-
p_dy = dy + bos * stride_dy_t
|
| 479 |
-
p_dx = dx + bos * stride_dx_t
|
| 480 |
-
else:
|
| 481 |
-
i_t = i_t + CHUNK_OFFSET
|
| 482 |
-
i_tg = i_b * NT + i_t
|
| 483 |
-
i_n = i_b
|
| 484 |
-
p_x = x + tl.cast(i_b, tl.int64) * stride_x_n
|
| 485 |
-
p_dy = dy + tl.cast(i_b, tl.int64) * stride_dy_n
|
| 486 |
-
p_dx = dx + tl.cast(i_b, tl.int64) * stride_dx_n
|
| 487 |
-
|
| 488 |
-
o_d = i_d * BD + tl.arange(0, BD)
|
| 489 |
-
o_w = tl.arange(0, BW) + W - BW
|
| 490 |
-
m_d = o_d < D
|
| 491 |
-
m_w = o_w >= 0
|
| 492 |
-
|
| 493 |
-
o_t = i_t * BT + tl.arange(0, BT)
|
| 494 |
-
m_t = (o_t >= 0) & (o_t < T)
|
| 495 |
-
|
| 496 |
-
b_x = tl.zeros((BT, BD), dtype=tl.float32)
|
| 497 |
-
if HAS_WEIGHT:
|
| 498 |
-
b_x = tl.load(
|
| 499 |
-
p_x + o_t[:, None] * stride_x_t + o_d[None, :] * stride_x_d,
|
| 500 |
-
mask=m_t[:, None] & m_d[None, :],
|
| 501 |
-
other=0,
|
| 502 |
-
).to(tl.float32)
|
| 503 |
-
b_w = tl.load(weight + o_d[:, None] * W + o_w, mask=m_d[:, None] & m_w, other=0).to(tl.float32)
|
| 504 |
-
|
| 505 |
-
b_dx = tl.zeros((BT, BD), dtype=tl.float32)
|
| 506 |
-
if HAS_BIAS:
|
| 507 |
-
b_db = tl.zeros((BD,), dtype=tl.float32)
|
| 508 |
-
|
| 509 |
-
for i_w in tl.static_range(0, W):
|
| 510 |
-
o_dy = o_t + i_w
|
| 511 |
-
m_dy = ((o_dy >= 0) & (o_dy < T))[:, None] & m_d[None, :]
|
| 512 |
-
b_dy = tl.load(
|
| 513 |
-
p_dy + o_dy[:, None] * stride_dy_t + o_d[None, :] * stride_dy_d,
|
| 514 |
-
mask=m_dy,
|
| 515 |
-
other=0,
|
| 516 |
-
).to(tl.float32)
|
| 517 |
-
|
| 518 |
-
if HAS_WEIGHT:
|
| 519 |
-
b_wdy = b_dy * tl.sum(b_w * (o_w == (W - i_w - 1)), 1)[None, :]
|
| 520 |
-
b_dw = tl.sum(b_dy * b_x, 0)
|
| 521 |
-
if USE_INITIAL_STATE:
|
| 522 |
-
mask_head_rows = (o_t < i_w) & (o_t < T)
|
| 523 |
-
b_dy_head = tl.load(
|
| 524 |
-
p_dy + o_t[:, None] * stride_dy_t + o_d[None, :] * stride_dy_d,
|
| 525 |
-
mask=(mask_head_rows[:, None] & m_d[None, :]),
|
| 526 |
-
other=0.0,
|
| 527 |
-
).to(tl.float32)
|
| 528 |
-
o_c = W - i_w + o_t
|
| 529 |
-
mask_c = (mask_head_rows & (o_c >= 1) & (o_c < W))
|
| 530 |
-
b_xc = tl.load(
|
| 531 |
-
initial_state + i_n * D * W + o_d[None, :] * W + o_c[:, None],
|
| 532 |
-
mask=(mask_c[:, None] & m_d[None, :]),
|
| 533 |
-
other=0.0,
|
| 534 |
-
).to(tl.float32)
|
| 535 |
-
b_dw += tl.sum(b_dy_head * b_xc, 0)
|
| 536 |
-
tl.store(dw + i_tg * D * W + o_d * W + W - i_w - 1, b_dw.to(dw.dtype.element_ty), mask=m_d)
|
| 537 |
-
else:
|
| 538 |
-
b_wdy = b_dy
|
| 539 |
-
|
| 540 |
-
if HAS_BIAS and i_w == 0:
|
| 541 |
-
b_db += tl.sum(b_dy, 0)
|
| 542 |
-
b_dx += b_wdy
|
| 543 |
-
|
| 544 |
-
if HAS_BIAS:
|
| 545 |
-
b_db = tl.cast(b_db, dtype=db.dtype.element_ty, fp_downcast_rounding='rtne')
|
| 546 |
-
tl.store(db + i_tg * D + o_d, b_db, mask=m_d)
|
| 547 |
-
|
| 548 |
-
if USE_FINAL_STATE:
|
| 549 |
-
if i_t * BT + BT >= T - W:
|
| 550 |
-
start_tok = T - (W - 1)
|
| 551 |
-
offset = i_t * BT + tl.arange(0, BT)
|
| 552 |
-
tok_idx = offset - start_tok
|
| 553 |
-
mask = (offset >= start_tok) & (offset < T)
|
| 554 |
-
w_idx = 1 + tok_idx
|
| 555 |
-
dht_off = i_n * D * W + o_d[None, :] * W + w_idx[:, None]
|
| 556 |
-
b_dht = tl.load(dht + dht_off, mask=mask[:, None] & m_d[None, :], other=0.).to(tl.float32)
|
| 557 |
-
b_dx += b_dht
|
| 558 |
-
|
| 559 |
-
tl.store(
|
| 560 |
-
p_dx + o_t[:, None] * stride_dx_t + o_d[None, :] * stride_dx_d,
|
| 561 |
-
tl.cast(b_dx, dtype=dx.dtype.element_ty, fp_downcast_rounding='rtne'),
|
| 562 |
-
mask=m_t[:, None] & m_d[None, :],
|
| 563 |
-
)
|
| 564 |
-
|
| 565 |
-
|
| 566 |
-
@triton.heuristics({
|
| 567 |
-
'USE_ACTIVATION': lambda args: args['y'] is not None,
|
| 568 |
-
'IS_VARLEN': lambda args: args['cu_seqlens'] is not None,
|
| 569 |
-
})
|
| 570 |
-
@triton.jit
|
| 571 |
-
def compute_dh0_kernel(
|
| 572 |
-
dy,
|
| 573 |
-
y,
|
| 574 |
-
weight,
|
| 575 |
-
dh0,
|
| 576 |
-
cu_seqlens,
|
| 577 |
-
stride_dy_n,
|
| 578 |
-
stride_dy_t,
|
| 579 |
-
stride_dy_d,
|
| 580 |
-
stride_y_n,
|
| 581 |
-
stride_y_t,
|
| 582 |
-
stride_y_d,
|
| 583 |
-
T,
|
| 584 |
-
D: tl.constexpr,
|
| 585 |
-
W: tl.constexpr,
|
| 586 |
-
BD: tl.constexpr,
|
| 587 |
-
USE_ACTIVATION: tl.constexpr,
|
| 588 |
-
IS_VARLEN: tl.constexpr,
|
| 589 |
-
CHUNK_OFFSET: tl.constexpr,
|
| 590 |
-
):
|
| 591 |
-
i_d, i_n = tl.program_id(0), tl.program_id(1) + CHUNK_OFFSET
|
| 592 |
-
|
| 593 |
-
if IS_VARLEN:
|
| 594 |
-
bos = tl.load(cu_seqlens + i_n).to(tl.int64)
|
| 595 |
-
eos = tl.load(cu_seqlens + i_n + 1).to(tl.int64)
|
| 596 |
-
seq_len = eos - bos
|
| 597 |
-
dy_base = dy + bos * stride_dy_t
|
| 598 |
-
else:
|
| 599 |
-
seq_len = T
|
| 600 |
-
dy_base = dy + tl.cast(i_n, tl.int64) * stride_dy_n
|
| 601 |
-
|
| 602 |
-
o_d = i_d * BD + tl.arange(0, BD)
|
| 603 |
-
m_d = o_d < D
|
| 604 |
-
|
| 605 |
-
for i_w in tl.static_range(1, W):
|
| 606 |
-
b_dh0 = tl.zeros([BD], dtype=tl.float32)
|
| 607 |
-
|
| 608 |
-
for t in tl.static_range(0, W - 1):
|
| 609 |
-
if t < i_w:
|
| 610 |
-
w_idx = i_w - 1 - t
|
| 611 |
-
p_dy = dy_base + t * stride_dy_t + o_d * stride_dy_d
|
| 612 |
-
m_t = (t < seq_len) & m_d
|
| 613 |
-
b_dy = tl.load(p_dy, mask=m_t, other=0).to(tl.float32)
|
| 614 |
-
|
| 615 |
-
if USE_ACTIVATION:
|
| 616 |
-
if IS_VARLEN:
|
| 617 |
-
p_y = y + bos * stride_y_t + t * stride_y_t + o_d * stride_y_d
|
| 618 |
-
else:
|
| 619 |
-
p_y = y + tl.cast(i_n, tl.int64) * stride_y_n + t * stride_y_t + o_d * stride_y_d
|
| 620 |
-
b_y = tl.load(p_y, mask=m_t, other=0).to(tl.float32)
|
| 621 |
-
b_ys = tl.sigmoid(b_y)
|
| 622 |
-
b_dy = b_dy * b_ys * (1 + b_y * (1 - b_ys))
|
| 623 |
-
|
| 624 |
-
b_w_col = tl.load(weight + o_d * W + w_idx, mask=m_d, other=0).to(tl.float32)
|
| 625 |
-
b_dh0 += tl.where(m_t, b_dy * b_w_col, 0)
|
| 626 |
-
|
| 627 |
-
p_dh0 = dh0 + i_n * D * W + o_d * W + i_w
|
| 628 |
-
tl.store(p_dh0, b_dh0.to(dh0.dtype.element_ty), mask=m_d)
|
| 629 |
-
|
| 630 |
-
|
| 631 |
-
@triton.heuristics({
|
| 632 |
-
'USE_INITIAL_STATE': lambda args: args['initial_state'] is not None,
|
| 633 |
-
'IS_VARLEN': lambda args: args['cu_seqlens'] is not None,
|
| 634 |
-
})
|
| 635 |
-
@triton.jit
|
| 636 |
-
def causal_conv1d_states_fwd_kernel(
|
| 637 |
-
x,
|
| 638 |
-
initial_state,
|
| 639 |
-
final_state,
|
| 640 |
-
cu_seqlens,
|
| 641 |
-
T,
|
| 642 |
-
D,
|
| 643 |
-
W,
|
| 644 |
-
stride_x_n,
|
| 645 |
-
stride_x_t,
|
| 646 |
-
stride_x_d,
|
| 647 |
-
BD: tl.constexpr,
|
| 648 |
-
BW: tl.constexpr,
|
| 649 |
-
USE_INITIAL_STATE: tl.constexpr,
|
| 650 |
-
IS_VARLEN: tl.constexpr,
|
| 651 |
-
CHUNK_OFFSET: tl.constexpr,
|
| 652 |
-
):
|
| 653 |
-
i_d, i_n = tl.program_id(0), tl.program_id(1) + CHUNK_OFFSET
|
| 654 |
-
|
| 655 |
-
o_d = i_d * BD + tl.arange(0, BD)
|
| 656 |
-
m_d = o_d < D
|
| 657 |
-
|
| 658 |
-
if IS_VARLEN:
|
| 659 |
-
bos = tl.load(cu_seqlens + i_n).to(tl.int64)
|
| 660 |
-
eos = tl.load(cu_seqlens + i_n + 1).to(tl.int64)
|
| 661 |
-
seq_len = (eos - bos).to(tl.int32)
|
| 662 |
-
p_x = x + bos * stride_x_t
|
| 663 |
-
else:
|
| 664 |
-
seq_len = T
|
| 665 |
-
p_x = x + tl.cast(i_n, tl.int64) * stride_x_n
|
| 666 |
-
|
| 667 |
-
o_w = W - BW + tl.arange(0, BW)
|
| 668 |
-
m_w = o_w >= 0
|
| 669 |
-
o_t = seq_len - BW + tl.arange(0, BW)
|
| 670 |
-
m_t = (o_t >= 0) & (o_t < seq_len)
|
| 671 |
-
|
| 672 |
-
b_x = tl.load(
|
| 673 |
-
p_x + o_t[:, None] * stride_x_t + o_d[None, :] * stride_x_d,
|
| 674 |
-
mask=m_t[:, None] & m_d[None, :],
|
| 675 |
-
other=0,
|
| 676 |
-
).to(tl.float32)
|
| 677 |
-
|
| 678 |
-
if USE_INITIAL_STATE:
|
| 679 |
-
if seq_len < BW:
|
| 680 |
-
o_c = W - (BW - seq_len) + tl.arange(0, BW)
|
| 681 |
-
m_c = (o_c >= 0) & (o_c < W)
|
| 682 |
-
b_cache = tl.load(
|
| 683 |
-
initial_state + i_n * D * W + o_d[None, :] * W + o_c[:, None],
|
| 684 |
-
mask=m_d[None, :] & m_c[:, None],
|
| 685 |
-
other=0,
|
| 686 |
-
).to(tl.float32)
|
| 687 |
-
b_x += b_cache
|
| 688 |
-
|
| 689 |
-
p_final = final_state + tl.cast(i_n, tl.int64) * D * W + o_d[:, None] * W + o_w[None, :]
|
| 690 |
-
tl.store(p_final, tl.trans(b_x).to(final_state.dtype.element_ty), mask=m_d[:, None] & m_w[None, :])
|
| 691 |
-
|
| 692 |
-
|
| 693 |
-
@triton.heuristics({
|
| 694 |
-
'HAS_WEIGHT': lambda args: args['weight'] is not None,
|
| 695 |
-
'HAS_BIAS': lambda args: args['bias'] is not None,
|
| 696 |
-
})
|
| 697 |
-
@triton.jit
|
| 698 |
-
def causal_conv1d_update_kernel(
|
| 699 |
-
x,
|
| 700 |
-
cache,
|
| 701 |
-
y,
|
| 702 |
-
weight,
|
| 703 |
-
bias,
|
| 704 |
-
stride_x_n,
|
| 705 |
-
stride_x_d,
|
| 706 |
-
stride_y_n,
|
| 707 |
-
stride_y_d,
|
| 708 |
-
D: tl.constexpr,
|
| 709 |
-
W: tl.constexpr,
|
| 710 |
-
BD: tl.constexpr,
|
| 711 |
-
HAS_WEIGHT: tl.constexpr,
|
| 712 |
-
HAS_BIAS: tl.constexpr,
|
| 713 |
-
CHUNK_OFFSET: tl.constexpr,
|
| 714 |
-
):
|
| 715 |
-
i_d, i_n = tl.program_id(0), tl.program_id(1) + CHUNK_OFFSET
|
| 716 |
-
|
| 717 |
-
o_d = i_d * BD + tl.arange(0, BD)
|
| 718 |
-
m_d = o_d < D
|
| 719 |
-
|
| 720 |
-
b_x = tl.load(x + i_n * stride_x_n + o_d * stride_x_d, mask=m_d, other=0).to(tl.float32)
|
| 721 |
-
|
| 722 |
-
b_y = tl.zeros((BD,), dtype=tl.float32)
|
| 723 |
-
for iw in tl.static_range(0, W):
|
| 724 |
-
if iw < W - 1:
|
| 725 |
-
b_c = tl.load(cache + i_n * D * W + o_d * W + (iw + 1), mask=m_d, other=0).to(tl.float32)
|
| 726 |
-
else:
|
| 727 |
-
b_c = b_x
|
| 728 |
-
tl.store(
|
| 729 |
-
cache + i_n * D * W + o_d * W + iw,
|
| 730 |
-
tl.cast(b_c, dtype=cache.dtype.element_ty, fp_downcast_rounding='rtne'),
|
| 731 |
-
mask=m_d,
|
| 732 |
-
)
|
| 733 |
-
if HAS_WEIGHT:
|
| 734 |
-
b_y += b_c * tl.load(weight + o_d * W + iw, mask=m_d, other=0).to(tl.float32)
|
| 735 |
-
else:
|
| 736 |
-
b_y += b_c
|
| 737 |
-
|
| 738 |
-
if HAS_BIAS:
|
| 739 |
-
b_y += tl.load(bias + o_d, mask=m_d)
|
| 740 |
-
|
| 741 |
-
tl.store(
|
| 742 |
-
y + i_n * stride_y_n + o_d * stride_y_d,
|
| 743 |
-
tl.cast(b_y, dtype=y.dtype.element_ty, fp_downcast_rounding='rtne'),
|
| 744 |
-
mask=m_d,
|
| 745 |
-
)
|
| 746 |
-
|
| 747 |
-
|
| 748 |
-
def _postprocess_update(
|
| 749 |
-
y: torch.Tensor,
|
| 750 |
-
residual: torch.Tensor | None,
|
| 751 |
-
activation: str | None,
|
| 752 |
-
) -> torch.Tensor:
|
| 753 |
-
if activation in ('swish', 'silu'):
|
| 754 |
-
y = _launch_silu(y)
|
| 755 |
-
if residual is not None:
|
| 756 |
-
if residual.stride() != y.stride():
|
| 757 |
-
residual = residual.contiguous()
|
| 758 |
-
y = _launch_add(y, residual)
|
| 759 |
-
return y
|
| 760 |
-
|
| 761 |
-
|
| 762 |
-
def _launch_fwd_core(
|
| 763 |
-
x: torch.Tensor,
|
| 764 |
-
weight: torch.Tensor,
|
| 765 |
-
bias: torch.Tensor,
|
| 766 |
-
initial_state: torch.Tensor | None,
|
| 767 |
-
cu_seqlens: torch.LongTensor | None,
|
| 768 |
-
chunk_indices: torch.LongTensor | None,
|
| 769 |
-
B: int,
|
| 770 |
-
T: int,
|
| 771 |
-
D: int,
|
| 772 |
-
W: int,
|
| 773 |
-
BT: int,
|
| 774 |
-
BD: int | None = None,
|
| 775 |
-
num_warps: int | None = None,
|
| 776 |
-
) -> torch.Tensor:
|
| 777 |
-
if BD is None or num_warps is None:
|
| 778 |
-
BD, BT, num_warps = _npu_tile_config(T, BT, D, x.dtype, initial_state)
|
| 779 |
-
NT = len(chunk_indices) if cu_seqlens is not None else triton.cdiv(T, BT)
|
| 780 |
-
BD = _clamp_bd_for_grid(B, NT, D, BD)
|
| 781 |
-
BW = triton.next_power_of_2(W)
|
| 782 |
-
|
| 783 |
-
stride_x_n, stride_x_t, stride_x_d = x.stride()
|
| 784 |
-
y = torch.zeros_like(x, memory_format=torch.contiguous_format)
|
| 785 |
-
stride_y_n, stride_y_t, stride_y_d = y.stride()
|
| 786 |
-
|
| 787 |
-
max_nt = _npu_max_axis_chunks(triton.cdiv(D, BD), B)
|
| 788 |
-
kernel_kwargs = dict(
|
| 789 |
-
x=x,
|
| 790 |
-
y=y,
|
| 791 |
-
weight=weight,
|
| 792 |
-
bias=bias,
|
| 793 |
-
cu_seqlens=cu_seqlens,
|
| 794 |
-
initial_state=initial_state,
|
| 795 |
-
B=B,
|
| 796 |
-
T=T,
|
| 797 |
-
D=D,
|
| 798 |
-
W=W,
|
| 799 |
-
BT=BT,
|
| 800 |
-
BW=BW,
|
| 801 |
-
BD=BD,
|
| 802 |
-
stride_x_n=stride_x_n,
|
| 803 |
-
stride_x_t=stride_x_t,
|
| 804 |
-
stride_x_d=stride_x_d,
|
| 805 |
-
stride_y_n=stride_y_n,
|
| 806 |
-
stride_y_t=stride_y_t,
|
| 807 |
-
stride_y_d=stride_y_d,
|
| 808 |
-
num_warps=num_warps,
|
| 809 |
-
)
|
| 810 |
-
for nt_off in range(0, NT, max_nt):
|
| 811 |
-
nt_len = min(max_nt, NT - nt_off)
|
| 812 |
-
grid = (triton.cdiv(D, BD), nt_len, B)
|
| 813 |
-
if cu_seqlens is not None:
|
| 814 |
-
kernel_kwargs['chunk_indices'] = chunk_indices[nt_off:nt_off + nt_len]
|
| 815 |
-
kernel_kwargs['CHUNK_OFFSET'] = 0
|
| 816 |
-
else:
|
| 817 |
-
kernel_kwargs['chunk_indices'] = chunk_indices
|
| 818 |
-
kernel_kwargs['CHUNK_OFFSET'] = nt_off
|
| 819 |
-
causal_conv1d_fwd_kernel[grid](**kernel_kwargs)
|
| 820 |
-
return y
|
| 821 |
-
|
| 822 |
-
|
| 823 |
-
@input_guard(no_guard_contiguous=['x'])
|
| 824 |
-
def causal_conv1d_fwd_npu(
|
| 825 |
-
x: torch.Tensor,
|
| 826 |
-
weight: torch.Tensor,
|
| 827 |
-
bias: torch.Tensor,
|
| 828 |
-
residual: torch.Tensor,
|
| 829 |
-
initial_state: torch.Tensor | None = None,
|
| 830 |
-
output_final_state: bool = False,
|
| 831 |
-
activation: str | None = None,
|
| 832 |
-
cu_seqlens: torch.LongTensor | None = None,
|
| 833 |
-
cu_seqlens_cpu: torch.LongTensor | None = None,
|
| 834 |
-
chunk_indices: torch.LongTensor | None = None,
|
| 835 |
-
BT: int = 64,
|
| 836 |
-
layout_fallback: bool = False,
|
| 837 |
-
):
|
| 838 |
-
del layout_fallback
|
| 839 |
-
shape = x.shape
|
| 840 |
-
if x.shape[-1] != weight.shape[0]:
|
| 841 |
-
x = rearrange(x, 'b t ... -> b t (...)')
|
| 842 |
-
B, T, D = x.shape[0], x.shape[1], weight.shape[0]
|
| 843 |
-
W = weight.shape[1]
|
| 844 |
-
|
| 845 |
-
BD, BT, num_warps = _npu_tile_config(T, BT, D, x.dtype, initial_state)
|
| 846 |
-
if cu_seqlens is not None:
|
| 847 |
-
chunk_indices = prepare_chunk_indices(cu_seqlens, BT, cu_seqlens_cpu=cu_seqlens_cpu)
|
| 848 |
-
|
| 849 |
-
y = _launch_fwd_core(
|
| 850 |
-
x, weight, bias, initial_state, cu_seqlens, chunk_indices, B, T, D, W, BT, BD, num_warps,
|
| 851 |
-
)
|
| 852 |
-
y = _postprocess_fwd(y, residual, activation)
|
| 853 |
-
|
| 854 |
-
final_state = None
|
| 855 |
-
if output_final_state:
|
| 856 |
-
final_state = causal_conv1d_update_states_npu(
|
| 857 |
-
x=x,
|
| 858 |
-
state_len=W,
|
| 859 |
-
initial_state=initial_state,
|
| 860 |
-
cu_seqlens=cu_seqlens,
|
| 861 |
-
)
|
| 862 |
-
return y.view(shape), final_state
|
| 863 |
-
|
| 864 |
-
|
| 865 |
-
def causal_conv1d_bwd_npu(
|
| 866 |
-
x: torch.Tensor,
|
| 867 |
-
dy: torch.Tensor,
|
| 868 |
-
dht: torch.Tensor,
|
| 869 |
-
weight: torch.Tensor | None = None,
|
| 870 |
-
bias: torch.Tensor | None = None,
|
| 871 |
-
residual: torch.Tensor | None = None,
|
| 872 |
-
initial_state: torch.Tensor | None = None,
|
| 873 |
-
activation: str | None = None,
|
| 874 |
-
cu_seqlens: torch.Tensor | None = None,
|
| 875 |
-
cu_seqlens_cpu: torch.LongTensor | None = None,
|
| 876 |
-
chunk_indices: torch.LongTensor | None = None,
|
| 877 |
-
BT: int = 64,
|
| 878 |
-
layout_fallback: bool = False,
|
| 879 |
-
):
|
| 880 |
-
del layout_fallback
|
| 881 |
-
shape = x.shape
|
| 882 |
-
if x.shape[-1] != weight.shape[0]:
|
| 883 |
-
x = rearrange(x, 'b t ... -> b t (...)')
|
| 884 |
-
B, T, D = x.shape
|
| 885 |
-
W = weight.shape[1] if weight is not None else None
|
| 886 |
-
|
| 887 |
-
BD, BT, num_warps = _npu_bwd_tile_config(T, BT, D, x.dtype, initial_state)
|
| 888 |
-
if cu_seqlens is not None:
|
| 889 |
-
chunk_indices = prepare_chunk_indices(cu_seqlens, BT, cu_seqlens_cpu=cu_seqlens_cpu)
|
| 890 |
-
NT = len(chunk_indices) if cu_seqlens is not None else triton.cdiv(T, BT)
|
| 891 |
-
BD = _clamp_bd_for_grid(B, NT, D, BD)
|
| 892 |
-
BW = triton.next_power_of_2(W)
|
| 893 |
-
|
| 894 |
-
dr = dy if residual is not None else None
|
| 895 |
-
dy_conv = dy
|
| 896 |
-
|
| 897 |
-
y_pre = None
|
| 898 |
-
if activation in ('swish', 'silu'):
|
| 899 |
-
BD_f, BT_f, nw_f = _npu_tile_config(T, BT, D, x.dtype, initial_state)
|
| 900 |
-
chunk_indices_f = chunk_indices
|
| 901 |
-
if cu_seqlens is not None:
|
| 902 |
-
chunk_indices_f = prepare_chunk_indices(cu_seqlens, BT_f, cu_seqlens_cpu=cu_seqlens_cpu)
|
| 903 |
-
y_pre = _launch_fwd_core(
|
| 904 |
-
x, weight, bias, initial_state, cu_seqlens, chunk_indices_f,
|
| 905 |
-
B, T, D, W, BT_f, BD_f, nw_f,
|
| 906 |
-
)
|
| 907 |
-
dy_conv = _launch_silu_bwd(y_pre, dy)
|
| 908 |
-
|
| 909 |
-
stride_x_n, stride_x_t, stride_x_d = x.stride()
|
| 910 |
-
use_seq = _use_seq_bwd(T, x.dtype, initial_state, dht, cu_seqlens)
|
| 911 |
-
stride_dy_n, stride_dy_t, stride_dy_d = dy_conv.stride()
|
| 912 |
-
|
| 913 |
-
dx = torch.zeros_like(x)
|
| 914 |
-
stride_dx_n, stride_dx_t, stride_dx_d = dx.stride()
|
| 915 |
-
|
| 916 |
-
if use_seq:
|
| 917 |
-
block = 1024
|
| 918 |
-
dw = weight.new_empty(B * T, *weight.shape, dtype=torch.float) if weight is not None else None
|
| 919 |
-
db = bias.new_empty(B * T, *bias.shape, dtype=torch.float) if bias is not None else None
|
| 920 |
-
grid = (triton.cdiv(B * T * D, block),)
|
| 921 |
-
causal_conv1d_bwd_seq_kernel[grid](
|
| 922 |
-
x=x,
|
| 923 |
-
weight=weight,
|
| 924 |
-
dy=dy_conv,
|
| 925 |
-
dx=dx,
|
| 926 |
-
dw=dw,
|
| 927 |
-
db=db,
|
| 928 |
-
stride_x_n=stride_x_n,
|
| 929 |
-
stride_x_t=stride_x_t,
|
| 930 |
-
stride_x_d=stride_x_d,
|
| 931 |
-
stride_dx_n=stride_dx_n,
|
| 932 |
-
stride_dx_t=stride_dx_t,
|
| 933 |
-
stride_dx_d=stride_dx_d,
|
| 934 |
-
stride_dy_n=stride_dy_n,
|
| 935 |
-
stride_dy_t=stride_dy_t,
|
| 936 |
-
stride_dy_d=stride_dy_d,
|
| 937 |
-
B=B,
|
| 938 |
-
TC=T,
|
| 939 |
-
D=D,
|
| 940 |
-
W=W,
|
| 941 |
-
BLOCK=block,
|
| 942 |
-
num_warps=STATIC_WARPS,
|
| 943 |
-
)
|
| 944 |
-
else:
|
| 945 |
-
if not dy_conv.is_contiguous():
|
| 946 |
-
dy_conv = dy_conv.contiguous()
|
| 947 |
-
stride_dy_n, stride_dy_t, stride_dy_d = dy_conv.stride()
|
| 948 |
-
dw = weight.new_empty(B * NT, *weight.shape, dtype=torch.float) if weight is not None else None
|
| 949 |
-
db = bias.new_empty(B * NT, *bias.shape, dtype=torch.float) if bias is not None else None
|
| 950 |
-
max_nt = _npu_max_axis_chunks(triton.cdiv(D, BD), B)
|
| 951 |
-
kernel_kwargs = dict(
|
| 952 |
-
x=x,
|
| 953 |
-
weight=weight,
|
| 954 |
-
initial_state=initial_state,
|
| 955 |
-
dht=dht,
|
| 956 |
-
dy=dy_conv,
|
| 957 |
-
dx=dx,
|
| 958 |
-
cu_seqlens=cu_seqlens,
|
| 959 |
-
B=B,
|
| 960 |
-
T=T,
|
| 961 |
-
D=D,
|
| 962 |
-
W=W,
|
| 963 |
-
BT=BT,
|
| 964 |
-
BW=BW,
|
| 965 |
-
BD=BD,
|
| 966 |
-
stride_x_n=stride_x_n,
|
| 967 |
-
stride_x_t=stride_x_t,
|
| 968 |
-
stride_x_d=stride_x_d,
|
| 969 |
-
stride_dx_n=stride_dx_n,
|
| 970 |
-
stride_dx_t=stride_dx_t,
|
| 971 |
-
stride_dx_d=stride_dx_d,
|
| 972 |
-
stride_dy_n=stride_dy_n,
|
| 973 |
-
stride_dy_t=stride_dy_t,
|
| 974 |
-
stride_dy_d=stride_dy_d,
|
| 975 |
-
num_warps=num_warps,
|
| 976 |
-
NT=NT,
|
| 977 |
-
)
|
| 978 |
-
for nt_off in range(0, NT, max_nt):
|
| 979 |
-
nt_len = min(max_nt, NT - nt_off)
|
| 980 |
-
grid = (triton.cdiv(D, BD), nt_len, B)
|
| 981 |
-
if cu_seqlens is not None:
|
| 982 |
-
kernel_kwargs['chunk_indices'] = chunk_indices[nt_off:nt_off + nt_len]
|
| 983 |
-
kernel_kwargs['CHUNK_OFFSET'] = 0
|
| 984 |
-
kernel_kwargs['dw'] = dw[nt_off:nt_off + nt_len] if weight is not None else None
|
| 985 |
-
kernel_kwargs['db'] = db[nt_off:nt_off + nt_len] if bias is not None else None
|
| 986 |
-
else:
|
| 987 |
-
kernel_kwargs['chunk_indices'] = chunk_indices
|
| 988 |
-
kernel_kwargs['CHUNK_OFFSET'] = nt_off
|
| 989 |
-
kernel_kwargs['dw'] = dw
|
| 990 |
-
kernel_kwargs['db'] = db
|
| 991 |
-
causal_conv1d_bwd_kernel[grid](**kernel_kwargs)
|
| 992 |
-
if weight is not None:
|
| 993 |
-
dw = dw.sum(0).to(weight)
|
| 994 |
-
if bias is not None:
|
| 995 |
-
db = db.sum(0).to(bias)
|
| 996 |
-
|
| 997 |
-
dh0 = None
|
| 998 |
-
if initial_state is not None:
|
| 999 |
-
dh0 = compute_dh0_npu(
|
| 1000 |
-
dy=dy,
|
| 1001 |
-
y=y_pre,
|
| 1002 |
-
weight=weight,
|
| 1003 |
-
initial_state=initial_state,
|
| 1004 |
-
activation=activation,
|
| 1005 |
-
cu_seqlens=cu_seqlens,
|
| 1006 |
-
)
|
| 1007 |
-
|
| 1008 |
-
return dx.view(shape), dw, db, dr, dh0
|
| 1009 |
-
|
| 1010 |
-
|
| 1011 |
-
def compute_dh0_npu(
|
| 1012 |
-
dy: torch.Tensor,
|
| 1013 |
-
y: torch.Tensor | None,
|
| 1014 |
-
weight: torch.Tensor,
|
| 1015 |
-
initial_state: torch.Tensor,
|
| 1016 |
-
activation: str | None,
|
| 1017 |
-
cu_seqlens: torch.Tensor | None,
|
| 1018 |
-
) -> torch.Tensor:
|
| 1019 |
-
D, W = weight.shape
|
| 1020 |
-
N = initial_state.shape[0]
|
| 1021 |
-
T = dy.shape[1]
|
| 1022 |
-
|
| 1023 |
-
BD = 8 if dy.dtype == torch.float16 and activation in ('swish', 'silu') else 16
|
| 1024 |
-
dh0 = torch.zeros_like(initial_state)
|
| 1025 |
-
|
| 1026 |
-
stride_dy_n = dy.stride(0)
|
| 1027 |
-
stride_dy_t = dy.stride(1)
|
| 1028 |
-
stride_dy_d = dy.stride(2) if dy.dim() == 3 else dy.stride(-1)
|
| 1029 |
-
stride_y_n = stride_y_t = stride_y_d = 0
|
| 1030 |
-
if y is not None:
|
| 1031 |
-
stride_y_n = y.stride(0)
|
| 1032 |
-
stride_y_t = y.stride(1)
|
| 1033 |
-
stride_y_d = y.stride(2) if y.dim() == 3 else y.stride(-1)
|
| 1034 |
-
|
| 1035 |
-
max_n = _npu_max_axis_chunks(triton.cdiv(D, BD))
|
| 1036 |
-
kernel_kwargs = dict(
|
| 1037 |
-
dy=dy,
|
| 1038 |
-
y=y if activation in ('swish', 'silu') else None,
|
| 1039 |
-
weight=weight,
|
| 1040 |
-
dh0=dh0,
|
| 1041 |
-
cu_seqlens=cu_seqlens,
|
| 1042 |
-
stride_dy_n=stride_dy_n,
|
| 1043 |
-
stride_dy_t=stride_dy_t,
|
| 1044 |
-
stride_dy_d=stride_dy_d,
|
| 1045 |
-
stride_y_n=stride_y_n,
|
| 1046 |
-
stride_y_t=stride_y_t,
|
| 1047 |
-
stride_y_d=stride_y_d,
|
| 1048 |
-
T=T,
|
| 1049 |
-
D=D,
|
| 1050 |
-
W=W,
|
| 1051 |
-
BD=BD,
|
| 1052 |
-
num_warps=STATIC_WARPS,
|
| 1053 |
-
)
|
| 1054 |
-
for n_off in range(0, N, max_n):
|
| 1055 |
-
n_len = min(max_n, N - n_off)
|
| 1056 |
-
kernel_kwargs['CHUNK_OFFSET'] = n_off
|
| 1057 |
-
compute_dh0_kernel[(triton.cdiv(D, BD), n_len)](**kernel_kwargs)
|
| 1058 |
-
return dh0
|
| 1059 |
-
|
| 1060 |
-
|
| 1061 |
-
@input_guard(no_guard_contiguous=['x'])
|
| 1062 |
-
def causal_conv1d_update_states_npu(
|
| 1063 |
-
x: torch.Tensor,
|
| 1064 |
-
state_len: int,
|
| 1065 |
-
initial_state: torch.Tensor | None = None,
|
| 1066 |
-
cu_seqlens: torch.Tensor | None = None,
|
| 1067 |
-
layout_fallback: bool = False,
|
| 1068 |
-
) -> torch.Tensor:
|
| 1069 |
-
del layout_fallback
|
| 1070 |
-
if cu_seqlens is not None:
|
| 1071 |
-
N = len(cu_seqlens) - 1
|
| 1072 |
-
if x.dim() == 2:
|
| 1073 |
-
stride_x_n = 0
|
| 1074 |
-
stride_x_t, stride_x_d = x.stride()
|
| 1075 |
-
T = x.shape[0]
|
| 1076 |
-
else:
|
| 1077 |
-
stride_x_n = x.stride(0)
|
| 1078 |
-
stride_x_t, stride_x_d = x.stride(1), x.stride(2)
|
| 1079 |
-
T = x.shape[1]
|
| 1080 |
-
D = x.shape[-1]
|
| 1081 |
-
else:
|
| 1082 |
-
B, T, D = x.shape
|
| 1083 |
-
N = B
|
| 1084 |
-
stride_x_n, stride_x_t, stride_x_d = x.stride()
|
| 1085 |
-
|
| 1086 |
-
W = state_len
|
| 1087 |
-
final_state = torch.empty(N, D, W, dtype=x.dtype, device=x.device)
|
| 1088 |
-
BD = min(triton.next_power_of_2(D), 16)
|
| 1089 |
-
BW = triton.next_power_of_2(W)
|
| 1090 |
-
grid_dim0 = triton.cdiv(D, BD)
|
| 1091 |
-
max_n = _npu_max_axis_chunks(grid_dim0)
|
| 1092 |
-
kernel_kwargs = dict(
|
| 1093 |
-
x=x,
|
| 1094 |
-
initial_state=initial_state,
|
| 1095 |
-
final_state=final_state,
|
| 1096 |
-
cu_seqlens=cu_seqlens,
|
| 1097 |
-
T=T,
|
| 1098 |
-
D=D,
|
| 1099 |
-
W=W,
|
| 1100 |
-
stride_x_n=stride_x_n,
|
| 1101 |
-
stride_x_t=stride_x_t,
|
| 1102 |
-
stride_x_d=stride_x_d,
|
| 1103 |
-
BW=BW,
|
| 1104 |
-
BD=BD,
|
| 1105 |
-
num_warps=STATIC_WARPS,
|
| 1106 |
-
)
|
| 1107 |
-
for n_off in range(0, N, max_n):
|
| 1108 |
-
n_len = min(max_n, N - n_off)
|
| 1109 |
-
kernel_kwargs['CHUNK_OFFSET'] = n_off
|
| 1110 |
-
causal_conv1d_states_fwd_kernel[(grid_dim0, n_len)](**kernel_kwargs)
|
| 1111 |
-
return final_state
|
| 1112 |
-
|
| 1113 |
-
|
| 1114 |
-
@input_guard(no_guard_contiguous=['x'])
|
| 1115 |
-
def causal_conv1d_update_npu(
|
| 1116 |
-
x: torch.Tensor,
|
| 1117 |
-
cache: torch.Tensor,
|
| 1118 |
-
residual: torch.Tensor | None = None,
|
| 1119 |
-
weight: torch.Tensor | None = None,
|
| 1120 |
-
bias: torch.Tensor | None = None,
|
| 1121 |
-
activation: str | None = None,
|
| 1122 |
-
) -> tuple[torch.Tensor, torch.Tensor]:
|
| 1123 |
-
shape = x.shape
|
| 1124 |
-
if weight is not None and x.shape[-1] != weight.shape[0]:
|
| 1125 |
-
x = rearrange(x, 'b t ... -> b t (...)')
|
| 1126 |
-
|
| 1127 |
-
D = x.shape[-1]
|
| 1128 |
-
N = x.numel() // D
|
| 1129 |
-
W = weight.shape[1] if weight is not None else None
|
| 1130 |
-
BD = min(triton.next_power_of_2(D), 16)
|
| 1131 |
-
|
| 1132 |
-
if x.dim() == 2:
|
| 1133 |
-
stride_x_n = x.stride(0)
|
| 1134 |
-
stride_x_d = x.stride(1)
|
| 1135 |
-
elif x.dim() == 3 and x.shape[0] == 1:
|
| 1136 |
-
stride_x_n = x.stride(1)
|
| 1137 |
-
stride_x_d = x.stride(2)
|
| 1138 |
-
elif x.dim() == 3:
|
| 1139 |
-
stride_x_n = x.stride(0)
|
| 1140 |
-
stride_x_d = x.stride(2)
|
| 1141 |
-
else:
|
| 1142 |
-
raise ValueError(f"Unsupported input shape: {x.shape}")
|
| 1143 |
-
|
| 1144 |
-
y = torch.zeros_like(x, memory_format=torch.contiguous_format)
|
| 1145 |
-
|
| 1146 |
-
if y.dim() == 2:
|
| 1147 |
-
stride_y_n, stride_y_d = y.stride(0), y.stride(1)
|
| 1148 |
-
elif y.dim() == 3 and y.shape[0] == 1:
|
| 1149 |
-
stride_y_n, stride_y_d = y.stride(1), y.stride(2)
|
| 1150 |
-
elif y.dim() == 3:
|
| 1151 |
-
stride_y_n, stride_y_d = y.stride(0), y.stride(2)
|
| 1152 |
-
|
| 1153 |
-
grid_dim0 = triton.cdiv(D, BD)
|
| 1154 |
-
max_n = _npu_max_axis_chunks(grid_dim0)
|
| 1155 |
-
kernel_kwargs = dict(
|
| 1156 |
-
x=x,
|
| 1157 |
-
cache=cache,
|
| 1158 |
-
y=y,
|
| 1159 |
-
weight=weight,
|
| 1160 |
-
bias=bias,
|
| 1161 |
-
stride_x_n=stride_x_n,
|
| 1162 |
-
stride_x_d=stride_x_d,
|
| 1163 |
-
stride_y_n=stride_y_n,
|
| 1164 |
-
stride_y_d=stride_y_d,
|
| 1165 |
-
D=D,
|
| 1166 |
-
W=W,
|
| 1167 |
-
BD=BD,
|
| 1168 |
-
num_warps=STATIC_WARPS,
|
| 1169 |
-
)
|
| 1170 |
-
for n_off in range(0, N, max_n):
|
| 1171 |
-
n_len = min(max_n, N - n_off)
|
| 1172 |
-
kernel_kwargs['CHUNK_OFFSET'] = n_off
|
| 1173 |
-
causal_conv1d_update_kernel[(grid_dim0, n_len)](**kernel_kwargs)
|
| 1174 |
-
y = _postprocess_update(y, residual, activation)
|
| 1175 |
-
return y.view(shape), cache
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
build/torch-cuda/modules/backends/triton_ascend/fused_cross_entropy.py
DELETED
|
@@ -1,469 +0,0 @@
|
|
| 1 |
-
# Copyright (c) 2023-2026, Songlin Yang, Yu Zhang, Zhiyuan Li
|
| 2 |
-
#
|
| 3 |
-
# This source code is licensed under the MIT license found in the
|
| 4 |
-
# LICENSE file in the root directory of this source tree.
|
| 5 |
-
# For a list of all contributors, visit:
|
| 6 |
-
# https://github.com/fla-org/flash-linear-attention/graphs/contributors
|
| 7 |
-
|
| 8 |
-
"""Fused cross-entropy kernels adapted for triton-ascend on Huawei NPU."""
|
| 9 |
-
|
| 10 |
-
import torch
|
| 11 |
-
import triton
|
| 12 |
-
import triton.language as tl
|
| 13 |
-
from triton.language.math import tanh
|
| 14 |
-
|
| 15 |
-
from ....ops.utils.op import exp, log
|
| 16 |
-
from ....utils import input_guard
|
| 17 |
-
from ....utils.ascend_ub_manager import (
|
| 18 |
-
ASCEND_MAX_GRID_DIM,
|
| 19 |
-
compute_vocab_block_size,
|
| 20 |
-
iter_axis_launch_chunks,
|
| 21 |
-
)
|
| 22 |
-
|
| 23 |
-
# Cross-entropy fwd/bwd peak fp32 buffers along vocab dimension.
|
| 24 |
-
_CE_FWD_MEM_MULT = 8.0
|
| 25 |
-
_CE_BWD_MEM_MULT = 12.0
|
| 26 |
-
|
| 27 |
-
|
| 28 |
-
@triton.heuristics({
|
| 29 |
-
"HAS_SMOOTHING": lambda args: args["label_smoothing"] > 0.0,
|
| 30 |
-
})
|
| 31 |
-
@triton.jit
|
| 32 |
-
def cross_entropy_fwd_kernel(
|
| 33 |
-
loss_ptr,
|
| 34 |
-
lse_ptr,
|
| 35 |
-
z_loss_ptr,
|
| 36 |
-
logits_ptr,
|
| 37 |
-
labels_ptr,
|
| 38 |
-
label_smoothing,
|
| 39 |
-
logit_scale,
|
| 40 |
-
lse_square_scale,
|
| 41 |
-
logit_softcapping: tl.constexpr,
|
| 42 |
-
ignore_index,
|
| 43 |
-
total_classes,
|
| 44 |
-
class_start_idx,
|
| 45 |
-
n_cols,
|
| 46 |
-
n_rows,
|
| 47 |
-
logits_row_stride,
|
| 48 |
-
ROW_OFFSET,
|
| 49 |
-
BLOCK_SIZE: tl.constexpr,
|
| 50 |
-
HAS_SMOOTHING: tl.constexpr,
|
| 51 |
-
HAS_SOFTCAPPING: tl.constexpr,
|
| 52 |
-
SPLIT: tl.constexpr,
|
| 53 |
-
):
|
| 54 |
-
row_idx = tl.program_id(0)
|
| 55 |
-
abs_row_idx = row_idx + ROW_OFFSET
|
| 56 |
-
col_block_idx = tl.program_id(1)
|
| 57 |
-
logits_ptr = logits_ptr + row_idx * logits_row_stride.to(tl.int64)
|
| 58 |
-
col_offsets = col_block_idx * BLOCK_SIZE + tl.arange(0, BLOCK_SIZE)
|
| 59 |
-
label_idx = tl.load(labels_ptr + row_idx)
|
| 60 |
-
logits = tl.load(logits_ptr + col_offsets, mask=col_offsets < n_cols, other=-float("inf"))
|
| 61 |
-
logits = logits.to(tl.float32) * logit_scale
|
| 62 |
-
if HAS_SOFTCAPPING:
|
| 63 |
-
logits = logit_softcapping * tanh(logits / logit_softcapping)
|
| 64 |
-
max_logits = tl.max(logits, 0)
|
| 65 |
-
if HAS_SMOOTHING:
|
| 66 |
-
sum_logits = tl.sum(tl.where(col_offsets < n_cols, logits, 0.0), 0)
|
| 67 |
-
lse = log(tl.sum(exp(logits - max_logits), 0)) + max_logits
|
| 68 |
-
tl.store(lse_ptr + col_block_idx * n_rows + abs_row_idx, lse)
|
| 69 |
-
if label_idx == ignore_index:
|
| 70 |
-
loss = 0.0
|
| 71 |
-
z_loss = 0.0
|
| 72 |
-
else:
|
| 73 |
-
label_idx -= class_start_idx
|
| 74 |
-
if label_idx >= col_block_idx * BLOCK_SIZE and label_idx < min(
|
| 75 |
-
n_cols, (col_block_idx + 1) * BLOCK_SIZE,
|
| 76 |
-
):
|
| 77 |
-
logits_label = tl.load(logits_ptr + label_idx).to(tl.float32) * logit_scale
|
| 78 |
-
if HAS_SOFTCAPPING:
|
| 79 |
-
logits_label = logit_softcapping * tanh(logits_label / logit_softcapping)
|
| 80 |
-
if HAS_SMOOTHING:
|
| 81 |
-
loss = (
|
| 82 |
-
(lse if not SPLIT else 0.0)
|
| 83 |
-
- label_smoothing * sum_logits / total_classes
|
| 84 |
-
- (1 - label_smoothing) * logits_label
|
| 85 |
-
)
|
| 86 |
-
else:
|
| 87 |
-
loss = (lse if not SPLIT else 0.0) - logits_label
|
| 88 |
-
else:
|
| 89 |
-
if HAS_SMOOTHING:
|
| 90 |
-
loss = label_smoothing * ((lse if not SPLIT else 0.0) - sum_logits / total_classes)
|
| 91 |
-
else:
|
| 92 |
-
loss = 0.0
|
| 93 |
-
if not SPLIT:
|
| 94 |
-
z_loss = lse_square_scale * lse * lse
|
| 95 |
-
loss += z_loss
|
| 96 |
-
else:
|
| 97 |
-
z_loss = 0.0
|
| 98 |
-
tl.store(loss_ptr + col_block_idx * n_rows + abs_row_idx, loss)
|
| 99 |
-
if not SPLIT:
|
| 100 |
-
tl.store(z_loss_ptr + col_block_idx * n_rows + abs_row_idx, z_loss)
|
| 101 |
-
|
| 102 |
-
|
| 103 |
-
@triton.heuristics({
|
| 104 |
-
"HAS_SMOOTHING": lambda args: args["label_smoothing"] > 0.0,
|
| 105 |
-
})
|
| 106 |
-
@triton.jit
|
| 107 |
-
def cross_entropy_bwd_kernel(
|
| 108 |
-
dlogits_ptr,
|
| 109 |
-
dloss_ptr,
|
| 110 |
-
logits_ptr,
|
| 111 |
-
lse_ptr,
|
| 112 |
-
labels_ptr,
|
| 113 |
-
label_smoothing,
|
| 114 |
-
logit_scale,
|
| 115 |
-
lse_square_scale,
|
| 116 |
-
logit_softcapping: tl.constexpr,
|
| 117 |
-
ignore_index,
|
| 118 |
-
total_classes,
|
| 119 |
-
class_start_idx,
|
| 120 |
-
n_cols,
|
| 121 |
-
logits_row_stride,
|
| 122 |
-
dlogits_row_stride,
|
| 123 |
-
dloss_row_stride,
|
| 124 |
-
ROW_OFFSET,
|
| 125 |
-
BLOCK_SIZE: tl.constexpr,
|
| 126 |
-
HAS_SMOOTHING: tl.constexpr,
|
| 127 |
-
HAS_SOFTCAPPING: tl.constexpr,
|
| 128 |
-
):
|
| 129 |
-
row_idx = tl.program_id(0)
|
| 130 |
-
abs_row_idx = row_idx + ROW_OFFSET
|
| 131 |
-
col_block_idx = tl.program_id(1)
|
| 132 |
-
logits_ptr = logits_ptr + row_idx * logits_row_stride.to(tl.int64)
|
| 133 |
-
dlogits_ptr = dlogits_ptr + row_idx * dlogits_row_stride.to(tl.int64)
|
| 134 |
-
col_offsets = col_block_idx * BLOCK_SIZE + tl.arange(0, BLOCK_SIZE)
|
| 135 |
-
label_idx = tl.load(labels_ptr + row_idx)
|
| 136 |
-
if label_idx != ignore_index:
|
| 137 |
-
dloss = tl.load(dloss_ptr + abs_row_idx * dloss_row_stride)
|
| 138 |
-
else:
|
| 139 |
-
dloss = 0.0
|
| 140 |
-
logits = tl.load(logits_ptr + col_offsets, mask=col_offsets < n_cols, other=-float("inf")).to(
|
| 141 |
-
tl.float32,
|
| 142 |
-
) * logit_scale
|
| 143 |
-
if HAS_SOFTCAPPING:
|
| 144 |
-
t = tanh(logits / logit_softcapping)
|
| 145 |
-
logits = logit_softcapping * t
|
| 146 |
-
lse = tl.load(lse_ptr + abs_row_idx)
|
| 147 |
-
probs = exp(logits - lse)
|
| 148 |
-
probs += 2.0 * lse_square_scale * lse * probs
|
| 149 |
-
label_idx -= class_start_idx
|
| 150 |
-
if HAS_SMOOTHING:
|
| 151 |
-
smooth_negative = label_smoothing / total_classes
|
| 152 |
-
probs = tl.where(col_offsets == label_idx, probs - (1 - label_smoothing), probs) - smooth_negative
|
| 153 |
-
else:
|
| 154 |
-
probs = tl.where(col_offsets == label_idx, probs - 1.0, probs)
|
| 155 |
-
if HAS_SOFTCAPPING:
|
| 156 |
-
probs = probs * (1.0 - t * t)
|
| 157 |
-
tl.store(dlogits_ptr + col_offsets, (dloss * logit_scale) * probs, mask=col_offsets < n_cols)
|
| 158 |
-
|
| 159 |
-
|
| 160 |
-
def _npu_block_size(n_cols: int, n_rows: int, is_backward: bool = False) -> tuple[int, int]:
|
| 161 |
-
memory_multiplier = _CE_BWD_MEM_MULT if is_backward else _CE_FWD_MEM_MULT
|
| 162 |
-
block_size = compute_vocab_block_size(n_cols, n_rows, memory_multiplier)
|
| 163 |
-
num_warps = 2 if block_size <= 2048 else 4
|
| 164 |
-
return block_size, num_warps
|
| 165 |
-
|
| 166 |
-
|
| 167 |
-
def _launch_cross_entropy_fwd(
|
| 168 |
-
losses,
|
| 169 |
-
lse,
|
| 170 |
-
z_losses,
|
| 171 |
-
logits,
|
| 172 |
-
target,
|
| 173 |
-
*,
|
| 174 |
-
label_smoothing,
|
| 175 |
-
logit_scale,
|
| 176 |
-
lse_square_scale,
|
| 177 |
-
softcap_val,
|
| 178 |
-
ignore_index,
|
| 179 |
-
total_classes,
|
| 180 |
-
class_start_idx,
|
| 181 |
-
n_cols,
|
| 182 |
-
n_rows,
|
| 183 |
-
logits_stride,
|
| 184 |
-
BLOCK_SIZE,
|
| 185 |
-
has_softcapping,
|
| 186 |
-
num_warps,
|
| 187 |
-
split,
|
| 188 |
-
):
|
| 189 |
-
n_splits = triton.cdiv(n_cols, BLOCK_SIZE)
|
| 190 |
-
for row_off, row_len in iter_axis_launch_chunks(n_rows, n_splits, max_grid=ASCEND_MAX_GRID_DIM):
|
| 191 |
-
cross_entropy_fwd_kernel[(row_len, n_splits)](
|
| 192 |
-
losses,
|
| 193 |
-
lse,
|
| 194 |
-
z_losses,
|
| 195 |
-
logits[row_off:row_off + row_len],
|
| 196 |
-
target[row_off:row_off + row_len],
|
| 197 |
-
label_smoothing,
|
| 198 |
-
logit_scale,
|
| 199 |
-
lse_square_scale,
|
| 200 |
-
softcap_val,
|
| 201 |
-
ignore_index,
|
| 202 |
-
total_classes,
|
| 203 |
-
class_start_idx,
|
| 204 |
-
n_cols,
|
| 205 |
-
n_rows,
|
| 206 |
-
logits_stride,
|
| 207 |
-
row_off,
|
| 208 |
-
BLOCK_SIZE=BLOCK_SIZE,
|
| 209 |
-
HAS_SOFTCAPPING=has_softcapping,
|
| 210 |
-
num_warps=num_warps,
|
| 211 |
-
SPLIT=split,
|
| 212 |
-
)
|
| 213 |
-
|
| 214 |
-
|
| 215 |
-
def _launch_cross_entropy_bwd(
|
| 216 |
-
dlogits,
|
| 217 |
-
grad_losses,
|
| 218 |
-
logits,
|
| 219 |
-
lse,
|
| 220 |
-
target,
|
| 221 |
-
*,
|
| 222 |
-
label_smoothing,
|
| 223 |
-
logit_scale,
|
| 224 |
-
lse_square_scale,
|
| 225 |
-
softcap_val,
|
| 226 |
-
ignore_index,
|
| 227 |
-
total_classes,
|
| 228 |
-
class_start_idx,
|
| 229 |
-
n_cols,
|
| 230 |
-
n_rows,
|
| 231 |
-
logits_stride,
|
| 232 |
-
dlogits_stride,
|
| 233 |
-
grad_losses_stride,
|
| 234 |
-
BLOCK_SIZE,
|
| 235 |
-
has_softcapping,
|
| 236 |
-
num_warps,
|
| 237 |
-
):
|
| 238 |
-
n_splits = triton.cdiv(n_cols, BLOCK_SIZE)
|
| 239 |
-
for row_off, row_len in iter_axis_launch_chunks(n_rows, n_splits, max_grid=ASCEND_MAX_GRID_DIM):
|
| 240 |
-
cross_entropy_bwd_kernel[(row_len, n_splits)](
|
| 241 |
-
dlogits[row_off:row_off + row_len],
|
| 242 |
-
grad_losses,
|
| 243 |
-
logits[row_off:row_off + row_len],
|
| 244 |
-
lse,
|
| 245 |
-
target[row_off:row_off + row_len],
|
| 246 |
-
label_smoothing,
|
| 247 |
-
logit_scale,
|
| 248 |
-
lse_square_scale,
|
| 249 |
-
softcap_val,
|
| 250 |
-
ignore_index,
|
| 251 |
-
total_classes,
|
| 252 |
-
class_start_idx,
|
| 253 |
-
n_cols,
|
| 254 |
-
logits_stride,
|
| 255 |
-
dlogits_stride,
|
| 256 |
-
grad_losses_stride,
|
| 257 |
-
row_off,
|
| 258 |
-
BLOCK_SIZE=BLOCK_SIZE,
|
| 259 |
-
HAS_SOFTCAPPING=has_softcapping,
|
| 260 |
-
num_warps=num_warps,
|
| 261 |
-
)
|
| 262 |
-
|
| 263 |
-
|
| 264 |
-
def fused_cross_entropy_forward_npu(
|
| 265 |
-
logits: torch.Tensor,
|
| 266 |
-
target: torch.Tensor,
|
| 267 |
-
label_smoothing: float = 0.0,
|
| 268 |
-
logit_scale: float = 1.0,
|
| 269 |
-
lse_square_scale: float = 0.0,
|
| 270 |
-
logit_softcapping: float = None,
|
| 271 |
-
ignore_index: int = -100,
|
| 272 |
-
process_group=None,
|
| 273 |
-
):
|
| 274 |
-
n_rows, n_cols = logits.shape
|
| 275 |
-
assert target.shape == (n_rows,)
|
| 276 |
-
world_size = 1 if process_group is None else torch.distributed.get_world_size(process_group)
|
| 277 |
-
total_classes = world_size * n_cols
|
| 278 |
-
rank = 0 if process_group is None else torch.distributed.get_rank(process_group)
|
| 279 |
-
class_start_idx = rank * n_cols
|
| 280 |
-
|
| 281 |
-
if logits.stride(-1) != 1:
|
| 282 |
-
logits = logits.contiguous()
|
| 283 |
-
|
| 284 |
-
MAX_BLOCK_SIZE = 64 * 1024
|
| 285 |
-
BLOCK_SIZE, num_warps = _npu_block_size(n_cols, n_rows)
|
| 286 |
-
has_softcapping = logit_softcapping is not None
|
| 287 |
-
softcap_val = float(logit_softcapping) if has_softcapping else 0.0
|
| 288 |
-
n_splits = (n_cols + BLOCK_SIZE - 1) // BLOCK_SIZE
|
| 289 |
-
split = world_size > 1 or n_cols > MAX_BLOCK_SIZE or n_splits > 1
|
| 290 |
-
loss_shape = (n_splits, n_rows) if n_splits > 1 else (n_rows,)
|
| 291 |
-
losses = torch.empty(*loss_shape, dtype=torch.float, device=logits.device)
|
| 292 |
-
lse = torch.empty(*loss_shape, dtype=torch.float, device=logits.device)
|
| 293 |
-
z_losses = torch.empty(*loss_shape, dtype=torch.float, device=logits.device)
|
| 294 |
-
|
| 295 |
-
_launch_cross_entropy_fwd(
|
| 296 |
-
losses,
|
| 297 |
-
lse,
|
| 298 |
-
z_losses,
|
| 299 |
-
logits,
|
| 300 |
-
target,
|
| 301 |
-
label_smoothing=label_smoothing,
|
| 302 |
-
logit_scale=logit_scale,
|
| 303 |
-
lse_square_scale=lse_square_scale,
|
| 304 |
-
softcap_val=softcap_val,
|
| 305 |
-
ignore_index=ignore_index,
|
| 306 |
-
total_classes=total_classes,
|
| 307 |
-
class_start_idx=class_start_idx,
|
| 308 |
-
n_cols=n_cols,
|
| 309 |
-
n_rows=n_rows,
|
| 310 |
-
logits_stride=logits.stride(0),
|
| 311 |
-
BLOCK_SIZE=BLOCK_SIZE,
|
| 312 |
-
has_softcapping=has_softcapping,
|
| 313 |
-
num_warps=num_warps,
|
| 314 |
-
split=split,
|
| 315 |
-
)
|
| 316 |
-
|
| 317 |
-
if split:
|
| 318 |
-
if n_splits > 1:
|
| 319 |
-
lse = torch.logsumexp(lse, dim=0)
|
| 320 |
-
losses = losses.sum(dim=0)
|
| 321 |
-
if world_size > 1:
|
| 322 |
-
lse_allgather = torch.empty(world_size, n_rows, dtype=lse.dtype, device=lse.device)
|
| 323 |
-
torch.distributed.all_gather_into_tensor(lse_allgather, lse, group=process_group)
|
| 324 |
-
handle_losses = torch.distributed.all_reduce(
|
| 325 |
-
losses, op=torch.distributed.ReduceOp.SUM, group=process_group, async_op=True,
|
| 326 |
-
)
|
| 327 |
-
lse = torch.logsumexp(lse_allgather, dim=0)
|
| 328 |
-
handle_losses.wait()
|
| 329 |
-
losses += lse
|
| 330 |
-
if lse_square_scale != 0.0:
|
| 331 |
-
z_losses = lse_square_scale * lse.square()
|
| 332 |
-
z_losses.masked_fill_(target == ignore_index, 0.0)
|
| 333 |
-
losses += z_losses
|
| 334 |
-
else:
|
| 335 |
-
z_losses = torch.zeros_like(losses)
|
| 336 |
-
losses.masked_fill_(target == ignore_index, 0.0)
|
| 337 |
-
|
| 338 |
-
return losses, z_losses, lse, total_classes, class_start_idx
|
| 339 |
-
|
| 340 |
-
|
| 341 |
-
def fused_cross_entropy_backward_npu(
|
| 342 |
-
dlogits: torch.Tensor,
|
| 343 |
-
grad_losses: torch.Tensor,
|
| 344 |
-
logits: torch.Tensor,
|
| 345 |
-
lse: torch.Tensor,
|
| 346 |
-
target: torch.Tensor,
|
| 347 |
-
label_smoothing: float,
|
| 348 |
-
logit_scale: float,
|
| 349 |
-
lse_square_scale: float,
|
| 350 |
-
logit_softcapping: float | None,
|
| 351 |
-
ignore_index: int,
|
| 352 |
-
total_classes: int,
|
| 353 |
-
class_start_idx: int,
|
| 354 |
-
) -> torch.Tensor:
|
| 355 |
-
n_rows, n_cols = logits.shape
|
| 356 |
-
BLOCK_SIZE, num_warps = _npu_block_size(n_cols, n_rows, is_backward=True)
|
| 357 |
-
has_softcapping = logit_softcapping is not None
|
| 358 |
-
softcap_val = float(logit_softcapping) if has_softcapping else 0.0
|
| 359 |
-
|
| 360 |
-
_launch_cross_entropy_bwd(
|
| 361 |
-
dlogits,
|
| 362 |
-
grad_losses,
|
| 363 |
-
logits,
|
| 364 |
-
lse,
|
| 365 |
-
target,
|
| 366 |
-
label_smoothing=label_smoothing,
|
| 367 |
-
logit_scale=logit_scale,
|
| 368 |
-
lse_square_scale=lse_square_scale,
|
| 369 |
-
softcap_val=softcap_val,
|
| 370 |
-
ignore_index=ignore_index,
|
| 371 |
-
total_classes=total_classes,
|
| 372 |
-
class_start_idx=class_start_idx,
|
| 373 |
-
n_cols=n_cols,
|
| 374 |
-
n_rows=n_rows,
|
| 375 |
-
logits_stride=logits.stride(0),
|
| 376 |
-
dlogits_stride=dlogits.stride(0),
|
| 377 |
-
grad_losses_stride=grad_losses.stride(0),
|
| 378 |
-
BLOCK_SIZE=BLOCK_SIZE,
|
| 379 |
-
has_softcapping=has_softcapping,
|
| 380 |
-
num_warps=num_warps,
|
| 381 |
-
)
|
| 382 |
-
return dlogits
|
| 383 |
-
|
| 384 |
-
|
| 385 |
-
class CrossEntropyLossFunctionNPU(torch.autograd.Function):
|
| 386 |
-
|
| 387 |
-
@staticmethod
|
| 388 |
-
@input_guard
|
| 389 |
-
def forward(
|
| 390 |
-
ctx,
|
| 391 |
-
logits,
|
| 392 |
-
target,
|
| 393 |
-
label_smoothing=0.0,
|
| 394 |
-
logit_scale=1.0,
|
| 395 |
-
lse_square_scale=0.0,
|
| 396 |
-
logit_softcapping=None,
|
| 397 |
-
ignore_index=-100,
|
| 398 |
-
inplace_backward=False,
|
| 399 |
-
process_group=None,
|
| 400 |
-
):
|
| 401 |
-
losses, z_losses, lse, total_classes, class_start_idx = fused_cross_entropy_forward_npu(
|
| 402 |
-
logits,
|
| 403 |
-
target,
|
| 404 |
-
label_smoothing,
|
| 405 |
-
logit_scale,
|
| 406 |
-
lse_square_scale,
|
| 407 |
-
logit_softcapping,
|
| 408 |
-
ignore_index,
|
| 409 |
-
process_group,
|
| 410 |
-
)
|
| 411 |
-
ctx.save_for_backward(logits, lse, target)
|
| 412 |
-
ctx.mark_non_differentiable(z_losses)
|
| 413 |
-
ctx.label_smoothing = label_smoothing
|
| 414 |
-
ctx.logit_scale = logit_scale
|
| 415 |
-
ctx.lse_square_scale = lse_square_scale
|
| 416 |
-
ctx.logit_softcapping = logit_softcapping
|
| 417 |
-
ctx.ignore_index = ignore_index
|
| 418 |
-
ctx.total_classes = total_classes
|
| 419 |
-
ctx.class_start_idx = class_start_idx
|
| 420 |
-
ctx.inplace_backward = inplace_backward
|
| 421 |
-
|
| 422 |
-
return losses, z_losses
|
| 423 |
-
|
| 424 |
-
@staticmethod
|
| 425 |
-
@input_guard
|
| 426 |
-
def backward(ctx, grad_losses, grad_z_losses):
|
| 427 |
-
del grad_z_losses
|
| 428 |
-
|
| 429 |
-
logits, lse, target = ctx.saved_tensors
|
| 430 |
-
dlogits = logits if ctx.inplace_backward else torch.empty_like(logits)
|
| 431 |
-
fused_cross_entropy_backward_npu(
|
| 432 |
-
dlogits,
|
| 433 |
-
grad_losses,
|
| 434 |
-
logits,
|
| 435 |
-
lse,
|
| 436 |
-
target,
|
| 437 |
-
ctx.label_smoothing,
|
| 438 |
-
ctx.logit_scale,
|
| 439 |
-
ctx.lse_square_scale,
|
| 440 |
-
ctx.logit_softcapping,
|
| 441 |
-
ctx.ignore_index,
|
| 442 |
-
ctx.total_classes,
|
| 443 |
-
ctx.class_start_idx,
|
| 444 |
-
)
|
| 445 |
-
return dlogits, None, None, None, None, None, None, None, None, None
|
| 446 |
-
|
| 447 |
-
|
| 448 |
-
def cross_entropy_loss_npu(
|
| 449 |
-
logits: torch.Tensor,
|
| 450 |
-
target: torch.Tensor,
|
| 451 |
-
label_smoothing: float = 0.0,
|
| 452 |
-
logit_scale: float = 1.0,
|
| 453 |
-
lse_square_scale: float = 0.0,
|
| 454 |
-
logit_softcapping: float = None,
|
| 455 |
-
ignore_index: int = -100,
|
| 456 |
-
inplace_backward: bool = False,
|
| 457 |
-
process_group=None,
|
| 458 |
-
) -> tuple[torch.Tensor, torch.Tensor]:
|
| 459 |
-
return CrossEntropyLossFunctionNPU.apply(
|
| 460 |
-
logits,
|
| 461 |
-
target,
|
| 462 |
-
label_smoothing,
|
| 463 |
-
logit_scale,
|
| 464 |
-
lse_square_scale,
|
| 465 |
-
logit_softcapping,
|
| 466 |
-
ignore_index,
|
| 467 |
-
inplace_backward,
|
| 468 |
-
process_group,
|
| 469 |
-
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
build/torch-cuda/modules/backends/triton_ascend/fused_kl_div.py
DELETED
|
@@ -1,188 +0,0 @@
|
|
| 1 |
-
# Copyright (c) 2023-2026, Songlin Yang, Yu Zhang, Zhiyuan Li
|
| 2 |
-
#
|
| 3 |
-
# This source code is licensed under the MIT license found in the
|
| 4 |
-
# LICENSE file in the root directory of this source tree.
|
| 5 |
-
# For a list of all contributors, visit:
|
| 6 |
-
# https://github.com/fla-org/flash-linear-attention/graphs/contributors
|
| 7 |
-
|
| 8 |
-
"""Fused KL divergence kernels adapted for triton-ascend on Huawei NPU."""
|
| 9 |
-
|
| 10 |
-
import torch
|
| 11 |
-
import torch.nn.functional as F
|
| 12 |
-
import triton
|
| 13 |
-
import triton.language as tl
|
| 14 |
-
|
| 15 |
-
from ....ops.utils.op import exp, log
|
| 16 |
-
from ....utils.ascend_ub_manager import ASCEND_MAX_GRID_DIM, compute_elementwise_block_size, compute_vocab_block_size
|
| 17 |
-
|
| 18 |
-
_KLD_FWD_MEM_MULT = 12.0
|
| 19 |
-
_ELEMENTWISE_MEM_MULT = 2.5
|
| 20 |
-
STATIC_WARPS = 2
|
| 21 |
-
|
| 22 |
-
|
| 23 |
-
@triton.jit
|
| 24 |
-
def kl_div_kernel(
|
| 25 |
-
logits,
|
| 26 |
-
target_logits,
|
| 27 |
-
loss,
|
| 28 |
-
s_logits,
|
| 29 |
-
s_loss,
|
| 30 |
-
reduction: tl.constexpr,
|
| 31 |
-
N: tl.constexpr,
|
| 32 |
-
V: tl.constexpr,
|
| 33 |
-
BV: tl.constexpr,
|
| 34 |
-
):
|
| 35 |
-
i_n = tl.program_id(0).to(tl.int64)
|
| 36 |
-
|
| 37 |
-
logits += i_n * s_logits
|
| 38 |
-
target_logits += i_n * s_logits
|
| 39 |
-
|
| 40 |
-
sm = float('-inf')
|
| 41 |
-
tm = float('-inf')
|
| 42 |
-
sd, td = 0.0, 0.0
|
| 43 |
-
|
| 44 |
-
NV = tl.cdiv(V, BV)
|
| 45 |
-
for iv in range(0, NV):
|
| 46 |
-
o_x = iv * BV + tl.arange(0, BV)
|
| 47 |
-
b_sl = tl.load(logits + o_x, mask=o_x < V, other=float('-inf'))
|
| 48 |
-
b_sm = tl.max(b_sl)
|
| 49 |
-
m_new = tl.maximum(sm, b_sm)
|
| 50 |
-
sd = sd * exp(sm - m_new) + tl.sum(exp(b_sl - m_new))
|
| 51 |
-
sm = m_new
|
| 52 |
-
|
| 53 |
-
b_tl = tl.load(target_logits + o_x, mask=o_x < V, other=float('-inf'))
|
| 54 |
-
b_tm = tl.max(b_tl)
|
| 55 |
-
m_new = tl.maximum(tm, b_tm)
|
| 56 |
-
td = td * exp(tm - m_new) + tl.sum(exp(b_tl - m_new))
|
| 57 |
-
tm = m_new
|
| 58 |
-
|
| 59 |
-
b_loss = 0.
|
| 60 |
-
for iv in range(0, NV):
|
| 61 |
-
o_x = iv * BV + tl.arange(0, BV)
|
| 62 |
-
b_sl = tl.load(logits + o_x, mask=o_x < V, other=float('-inf'))
|
| 63 |
-
b_tl = tl.load(target_logits + o_x, mask=o_x < V, other=float('-inf'))
|
| 64 |
-
b_sp_log = b_sl - sm - log(sd)
|
| 65 |
-
b_tp_log = b_tl - tm - log(td)
|
| 66 |
-
b_sp = exp(b_sp_log)
|
| 67 |
-
b_tp = exp(b_tp_log)
|
| 68 |
-
b_kl = tl.where(o_x < V, b_tp * (b_tp_log - b_sp_log), 0)
|
| 69 |
-
b_dl = -b_tp + b_sp
|
| 70 |
-
b_loss += tl.sum(b_kl)
|
| 71 |
-
if reduction == 'batchmean':
|
| 72 |
-
b_dl = b_dl / N
|
| 73 |
-
tl.store(logits + o_x, b_dl, mask=o_x < V)
|
| 74 |
-
|
| 75 |
-
if reduction == 'batchmean':
|
| 76 |
-
b_loss = b_loss / N
|
| 77 |
-
|
| 78 |
-
tl.store(loss + i_n * s_loss, b_loss)
|
| 79 |
-
|
| 80 |
-
|
| 81 |
-
@triton.jit
|
| 82 |
-
def elementwise_mul_kernel(
|
| 83 |
-
x,
|
| 84 |
-
g,
|
| 85 |
-
N: tl.constexpr,
|
| 86 |
-
B: tl.constexpr,
|
| 87 |
-
):
|
| 88 |
-
i_x = tl.program_id(0).to(tl.int64)
|
| 89 |
-
o_x = i_x * B + tl.arange(0, B)
|
| 90 |
-
|
| 91 |
-
b_g = tl.load(g)
|
| 92 |
-
b_x = tl.load(x + o_x, mask=o_x < N)
|
| 93 |
-
tl.store(x + o_x, b_x * b_g, mask=o_x < N)
|
| 94 |
-
|
| 95 |
-
|
| 96 |
-
def _npu_vocab_block_size(vocab_size: int, num_rows: int) -> int:
|
| 97 |
-
return compute_vocab_block_size(vocab_size, num_rows, _KLD_FWD_MEM_MULT)
|
| 98 |
-
|
| 99 |
-
|
| 100 |
-
def fused_kl_div_forward_npu(
|
| 101 |
-
x: torch.Tensor,
|
| 102 |
-
target_x: torch.Tensor,
|
| 103 |
-
weight: torch.Tensor,
|
| 104 |
-
target_weight: torch.Tensor,
|
| 105 |
-
reduction: str = 'batchmean',
|
| 106 |
-
accumulate_grad_in_fp32: bool = True,
|
| 107 |
-
):
|
| 108 |
-
device = x.device
|
| 109 |
-
|
| 110 |
-
N, H, V = *x.shape, weight.shape[0]
|
| 111 |
-
BV = _npu_vocab_block_size(V, N)
|
| 112 |
-
NC = min(8, triton.cdiv(V, H))
|
| 113 |
-
C = min(triton.next_power_of_2(triton.cdiv(N, NC)), ASCEND_MAX_GRID_DIM)
|
| 114 |
-
NC = triton.cdiv(N, C)
|
| 115 |
-
|
| 116 |
-
grad_dtype = torch.float32 if accumulate_grad_in_fp32 else weight.dtype
|
| 117 |
-
|
| 118 |
-
dx = torch.zeros_like(x, device=device)
|
| 119 |
-
dw = torch.zeros_like(weight, device=device, dtype=grad_dtype) if weight is not None else None
|
| 120 |
-
loss = torch.zeros(N, dtype=torch.float32, device=device)
|
| 121 |
-
|
| 122 |
-
for ic in range(NC):
|
| 123 |
-
start, end = ic * C, min((ic + 1) * C, N)
|
| 124 |
-
c_sx = x[start:end]
|
| 125 |
-
c_tx = target_x[start:end]
|
| 126 |
-
c_sl = F.linear(c_sx, weight)
|
| 127 |
-
c_tl = F.linear(c_tx, target_weight)
|
| 128 |
-
if weight is not None and c_sx.dtype != grad_dtype:
|
| 129 |
-
c_sx = c_sx.to(dtype=grad_dtype)
|
| 130 |
-
|
| 131 |
-
c_loss = loss[start:end]
|
| 132 |
-
|
| 133 |
-
kl_div_kernel[(c_sx.shape[0],)](
|
| 134 |
-
logits=c_sl,
|
| 135 |
-
target_logits=c_tl,
|
| 136 |
-
loss=c_loss,
|
| 137 |
-
s_logits=c_sl.stride(-2),
|
| 138 |
-
s_loss=c_loss.stride(-1),
|
| 139 |
-
reduction=reduction,
|
| 140 |
-
N=N,
|
| 141 |
-
V=V,
|
| 142 |
-
BV=BV,
|
| 143 |
-
num_warps=STATIC_WARPS,
|
| 144 |
-
)
|
| 145 |
-
|
| 146 |
-
c_grad = c_sl if c_sl.is_contiguous() else c_sl.contiguous()
|
| 147 |
-
dx[start:end] = torch.mm(c_grad, weight)
|
| 148 |
-
|
| 149 |
-
if weight is not None:
|
| 150 |
-
grad_w = c_grad.t().to(dtype=grad_dtype)
|
| 151 |
-
grad_x = c_sx if c_sx.dtype == grad_dtype else c_sx.to(dtype=grad_dtype)
|
| 152 |
-
dw.add_(grad_w @ grad_x)
|
| 153 |
-
|
| 154 |
-
loss = loss.sum()
|
| 155 |
-
if dw is not None:
|
| 156 |
-
dw = dw.to(weight)
|
| 157 |
-
return loss, dx, dw
|
| 158 |
-
|
| 159 |
-
|
| 160 |
-
def fused_kl_div_backward_npu(
|
| 161 |
-
do: torch.Tensor,
|
| 162 |
-
dx: torch.Tensor,
|
| 163 |
-
dw: torch.Tensor,
|
| 164 |
-
):
|
| 165 |
-
if torch.ne(do, torch.tensor(1.0, device=do.device)):
|
| 166 |
-
N, H = dx.shape
|
| 167 |
-
B = compute_elementwise_block_size(N * H, _ELEMENTWISE_MEM_MULT)
|
| 168 |
-
|
| 169 |
-
elementwise_mul_kernel[(triton.cdiv(N * H, B),)](
|
| 170 |
-
x=dx,
|
| 171 |
-
g=do,
|
| 172 |
-
N=N*H,
|
| 173 |
-
B=B,
|
| 174 |
-
num_warps=STATIC_WARPS,
|
| 175 |
-
)
|
| 176 |
-
|
| 177 |
-
if dw is not None:
|
| 178 |
-
V, H = dw.shape
|
| 179 |
-
B_dw = compute_elementwise_block_size(V * H, _ELEMENTWISE_MEM_MULT)
|
| 180 |
-
elementwise_mul_kernel[(triton.cdiv(V * H, B_dw),)](
|
| 181 |
-
x=dw,
|
| 182 |
-
g=do,
|
| 183 |
-
N=V*H,
|
| 184 |
-
B=B_dw,
|
| 185 |
-
num_warps=STATIC_WARPS,
|
| 186 |
-
)
|
| 187 |
-
|
| 188 |
-
return dx, dw
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
build/torch-cuda/modules/backends/triton_ascend/fused_linear_cross_entropy.py
DELETED
|
@@ -1,347 +0,0 @@
|
|
| 1 |
-
# Copyright (c) 2023-2026, Songlin Yang, Yu Zhang, Zhiyuan Li
|
| 2 |
-
#
|
| 3 |
-
# This source code is licensed under the MIT license found in the
|
| 4 |
-
# LICENSE file in the root directory of this source tree.
|
| 5 |
-
# For a list of all contributors, visit:
|
| 6 |
-
# https://github.com/fla-org/flash-linear-attention/graphs/contributors
|
| 7 |
-
|
| 8 |
-
"""Fused linear cross-entropy kernels adapted for triton-ascend on Huawei NPU."""
|
| 9 |
-
|
| 10 |
-
import torch
|
| 11 |
-
import torch.nn.functional as F
|
| 12 |
-
import triton
|
| 13 |
-
import triton.language as tl
|
| 14 |
-
from triton.language.math import tanh
|
| 15 |
-
|
| 16 |
-
from ....ops.utils.op import exp, log
|
| 17 |
-
from ....utils.ascend_ub_manager import (
|
| 18 |
-
ASCEND_MAX_GRID_DIM,
|
| 19 |
-
compute_elementwise_block_size,
|
| 20 |
-
compute_vocab_block_size,
|
| 21 |
-
iter_axis_launch_chunks,
|
| 22 |
-
)
|
| 23 |
-
|
| 24 |
-
# Fused linear CE: logsumexp forward vs gradient kernels along vocab.
|
| 25 |
-
_LCE_FWD_MEM_MULT = 8.0
|
| 26 |
-
_LCE_BWD_MEM_MULT = 12.0
|
| 27 |
-
_ELEMENTWISE_MEM_MULT = 2.5
|
| 28 |
-
STATIC_WARPS = 2
|
| 29 |
-
|
| 30 |
-
|
| 31 |
-
@triton.heuristics({
|
| 32 |
-
'HAS_SCALE': lambda args: args['scale'] is not None,
|
| 33 |
-
})
|
| 34 |
-
@triton.jit
|
| 35 |
-
def logsumexp_fwd_kernel(
|
| 36 |
-
x,
|
| 37 |
-
z,
|
| 38 |
-
scale,
|
| 39 |
-
softcapping: tl.constexpr,
|
| 40 |
-
D: tl.constexpr,
|
| 41 |
-
B: tl.constexpr,
|
| 42 |
-
ROWWISE: tl.constexpr,
|
| 43 |
-
HAS_SCALE: tl.constexpr,
|
| 44 |
-
HAS_SOFTCAPPING: tl.constexpr,
|
| 45 |
-
):
|
| 46 |
-
i_n = tl.program_id(0).to(tl.int64)
|
| 47 |
-
if ROWWISE:
|
| 48 |
-
row = x + i_n * D
|
| 49 |
-
m = float('-inf')
|
| 50 |
-
d = 0.0
|
| 51 |
-
for start in range(0, D, B):
|
| 52 |
-
o = start + tl.arange(0, B)
|
| 53 |
-
b_x = tl.load(row + o, mask=o < D, other=float('-inf')).to(tl.float32)
|
| 54 |
-
if HAS_SCALE:
|
| 55 |
-
b_x = b_x * scale
|
| 56 |
-
if HAS_SOFTCAPPING:
|
| 57 |
-
b_x = softcapping * tanh(b_x / softcapping)
|
| 58 |
-
blk_max = tl.max(b_x, 0)
|
| 59 |
-
new_m = tl.maximum(m, blk_max)
|
| 60 |
-
d = d * exp(m - new_m) + tl.sum(exp(b_x - new_m), 0)
|
| 61 |
-
m = new_m
|
| 62 |
-
tl.store(z + i_n, m + log(d))
|
| 63 |
-
else:
|
| 64 |
-
i_d = tl.program_id(1).to(tl.int64)
|
| 65 |
-
o_d = i_d * B + tl.arange(0, B)
|
| 66 |
-
m_d = o_d < D
|
| 67 |
-
|
| 68 |
-
b_x = tl.load(x + i_n * D + o_d, mask=m_d, other=-float('inf'))
|
| 69 |
-
if HAS_SCALE:
|
| 70 |
-
b_x = b_x * scale
|
| 71 |
-
if HAS_SOFTCAPPING:
|
| 72 |
-
b_x = softcapping * tanh(b_x / softcapping)
|
| 73 |
-
b_m = tl.max(b_x, 0)
|
| 74 |
-
b_z = log(tl.sum(exp(b_x - b_m), 0)) + b_m
|
| 75 |
-
tl.store(z + i_n * tl.cdiv(D, B) + i_d, b_z)
|
| 76 |
-
|
| 77 |
-
|
| 78 |
-
@triton.jit
|
| 79 |
-
def cross_entropy_kernel(
|
| 80 |
-
logits,
|
| 81 |
-
lse,
|
| 82 |
-
target,
|
| 83 |
-
loss,
|
| 84 |
-
total,
|
| 85 |
-
ignore_index,
|
| 86 |
-
label_smoothing: tl.constexpr,
|
| 87 |
-
logit_scale: tl.constexpr,
|
| 88 |
-
logit_softcapping: tl.constexpr,
|
| 89 |
-
HAS_SOFTCAPPING: tl.constexpr,
|
| 90 |
-
reduction: tl.constexpr,
|
| 91 |
-
V: tl.constexpr,
|
| 92 |
-
BV: tl.constexpr,
|
| 93 |
-
):
|
| 94 |
-
i_n = tl.program_id(0).to(tl.int64)
|
| 95 |
-
NV = tl.cdiv(V, BV)
|
| 96 |
-
|
| 97 |
-
b_y = tl.load(target + i_n)
|
| 98 |
-
logits += i_n * V
|
| 99 |
-
|
| 100 |
-
if b_y == ignore_index:
|
| 101 |
-
for i in range(0, V, BV):
|
| 102 |
-
o_v = i + tl.arange(0, BV)
|
| 103 |
-
tl.store(logits + o_v, 0.0, mask=o_v < V)
|
| 104 |
-
return
|
| 105 |
-
|
| 106 |
-
b_l = tl.load(logits + b_y).to(tl.float32) * logit_scale
|
| 107 |
-
if HAS_SOFTCAPPING:
|
| 108 |
-
b_t_y = tanh(b_l / logit_softcapping)
|
| 109 |
-
b_l = logit_softcapping * b_t_y
|
| 110 |
-
b_softcap_deriv_y = 1.0 - b_t_y * b_t_y
|
| 111 |
-
b_lse = tl.load(lse + i_n)
|
| 112 |
-
|
| 113 |
-
b_loss = b_lse - b_l
|
| 114 |
-
b_z = 0.0
|
| 115 |
-
eps = label_smoothing / V
|
| 116 |
-
|
| 117 |
-
for iv in range(0, NV):
|
| 118 |
-
o_v = iv * BV + tl.arange(0, BV)
|
| 119 |
-
b_logits = tl.load(logits + o_v, mask=o_v < V, other=float('-inf')).to(tl.float32) * logit_scale
|
| 120 |
-
if HAS_SOFTCAPPING:
|
| 121 |
-
b_t = tanh(b_logits / logit_softcapping)
|
| 122 |
-
b_capped = logit_softcapping * b_t
|
| 123 |
-
else:
|
| 124 |
-
b_capped = b_logits
|
| 125 |
-
if label_smoothing > 0:
|
| 126 |
-
b_z += tl.sum(tl.where(o_v < V, -eps * b_capped, 0.0))
|
| 127 |
-
b_p = (exp(b_capped - b_lse) - eps) * logit_scale
|
| 128 |
-
if HAS_SOFTCAPPING:
|
| 129 |
-
b_p = b_p * (1.0 - b_t * b_t)
|
| 130 |
-
if reduction == "mean":
|
| 131 |
-
b_p = b_p / total
|
| 132 |
-
tl.store(logits + o_v, b_p, mask=o_v < V)
|
| 133 |
-
|
| 134 |
-
if label_smoothing > 0:
|
| 135 |
-
b_loss = b_loss * (1 - label_smoothing) + (b_z + label_smoothing * b_lse)
|
| 136 |
-
|
| 137 |
-
b_l = tl.load(logits + b_y)
|
| 138 |
-
|
| 139 |
-
if HAS_SOFTCAPPING:
|
| 140 |
-
b_sc_factor = b_softcap_deriv_y
|
| 141 |
-
else:
|
| 142 |
-
b_sc_factor = 1.0
|
| 143 |
-
|
| 144 |
-
if reduction == 'mean':
|
| 145 |
-
b_loss = b_loss / total
|
| 146 |
-
b_l += (label_smoothing - 1) / total * logit_scale * b_sc_factor
|
| 147 |
-
else:
|
| 148 |
-
b_l += (label_smoothing - 1) * logit_scale * b_sc_factor
|
| 149 |
-
|
| 150 |
-
tl.store(loss + i_n, b_loss)
|
| 151 |
-
tl.store(logits + b_y, b_l)
|
| 152 |
-
|
| 153 |
-
|
| 154 |
-
@triton.jit
|
| 155 |
-
def elementwise_mul_kernel(
|
| 156 |
-
x,
|
| 157 |
-
g,
|
| 158 |
-
N: tl.constexpr,
|
| 159 |
-
B: tl.constexpr,
|
| 160 |
-
):
|
| 161 |
-
i_x = tl.program_id(0).to(tl.int64)
|
| 162 |
-
o_x = i_x * B + tl.arange(0, B)
|
| 163 |
-
|
| 164 |
-
b_g = tl.load(g)
|
| 165 |
-
b_x = tl.load(x + o_x, mask=o_x < N)
|
| 166 |
-
tl.store(x + o_x, b_x * b_g, mask=o_x < N)
|
| 167 |
-
|
| 168 |
-
|
| 169 |
-
def _npu_vocab_block_size(vocab_size: int, num_rows: int, is_backward: bool = True) -> int:
|
| 170 |
-
memory_multiplier = _LCE_BWD_MEM_MULT if is_backward else _LCE_FWD_MEM_MULT
|
| 171 |
-
return compute_vocab_block_size(vocab_size, num_rows, memory_multiplier)
|
| 172 |
-
|
| 173 |
-
|
| 174 |
-
def logsumexp_fwd_npu(
|
| 175 |
-
x,
|
| 176 |
-
scale: float | None = None,
|
| 177 |
-
softcapping: float | None = None,
|
| 178 |
-
dtype: torch.dtype | None = None,
|
| 179 |
-
):
|
| 180 |
-
shape = x.shape
|
| 181 |
-
x = x.view(-1, shape[-1])
|
| 182 |
-
N, D = x.shape
|
| 183 |
-
B = _npu_vocab_block_size(D, N, is_backward=False)
|
| 184 |
-
has_softcapping = softcapping is not None
|
| 185 |
-
softcap_val = float(softcapping) if has_softcapping else 0.0
|
| 186 |
-
|
| 187 |
-
z = x.new_empty(N, dtype=torch.float)
|
| 188 |
-
for row_off, row_len in iter_axis_launch_chunks(N, 1, max_grid=ASCEND_MAX_GRID_DIM):
|
| 189 |
-
logsumexp_fwd_kernel[(row_len,)](
|
| 190 |
-
x=x[row_off:row_off + row_len],
|
| 191 |
-
z=z[row_off:row_off + row_len],
|
| 192 |
-
scale=scale,
|
| 193 |
-
softcapping=softcap_val,
|
| 194 |
-
D=D,
|
| 195 |
-
B=B,
|
| 196 |
-
ROWWISE=True,
|
| 197 |
-
HAS_SOFTCAPPING=has_softcapping,
|
| 198 |
-
)
|
| 199 |
-
z = z.view(*shape[:-1])
|
| 200 |
-
if dtype is not None and dtype != torch.float:
|
| 201 |
-
z = z.to(dtype)
|
| 202 |
-
return z
|
| 203 |
-
|
| 204 |
-
|
| 205 |
-
def fused_linear_cross_entropy_forward_npu(
|
| 206 |
-
x: torch.Tensor,
|
| 207 |
-
target: torch.LongTensor,
|
| 208 |
-
weight: torch.Tensor,
|
| 209 |
-
bias: torch.Tensor = None,
|
| 210 |
-
ignore_index: int = -100,
|
| 211 |
-
label_smoothing: float = 0.0,
|
| 212 |
-
logit_scale: float = 1.0,
|
| 213 |
-
logit_softcapping: float = None,
|
| 214 |
-
num_chunks: int = 8,
|
| 215 |
-
reduction: str = "mean",
|
| 216 |
-
use_l2warp: bool = False,
|
| 217 |
-
l2_penalty_factor: float = 1e-4,
|
| 218 |
-
accumulate_grad_in_fp32: bool = True,
|
| 219 |
-
):
|
| 220 |
-
device = x.device
|
| 221 |
-
N, H, V = *x.shape, weight.shape[0]
|
| 222 |
-
BV = _npu_vocab_block_size(V, N)
|
| 223 |
-
has_softcapping = logit_softcapping is not None
|
| 224 |
-
softcap_val = float(logit_softcapping) if has_softcapping else 0.0
|
| 225 |
-
NC = min(num_chunks, triton.cdiv(V, H))
|
| 226 |
-
C = min(triton.next_power_of_2(triton.cdiv(N, NC)), ASCEND_MAX_GRID_DIM)
|
| 227 |
-
NC = triton.cdiv(N, C)
|
| 228 |
-
|
| 229 |
-
dx = torch.zeros_like(x, device=device)
|
| 230 |
-
grad_dtype = torch.float32 if accumulate_grad_in_fp32 else weight.dtype
|
| 231 |
-
bias_grad_dtype = None
|
| 232 |
-
if bias is not None:
|
| 233 |
-
bias_grad_dtype = torch.float32 if accumulate_grad_in_fp32 else bias.dtype
|
| 234 |
-
|
| 235 |
-
dw = torch.zeros_like(weight, device=device, dtype=grad_dtype) if weight is not None else None
|
| 236 |
-
db = torch.zeros_like(bias, device=device, dtype=bias_grad_dtype) if bias is not None else None
|
| 237 |
-
loss = torch.zeros(N, device=device, dtype=torch.float)
|
| 238 |
-
|
| 239 |
-
total = target.ne(ignore_index).sum().item()
|
| 240 |
-
|
| 241 |
-
for ic in range(NC):
|
| 242 |
-
start, end = ic * C, min((ic + 1) * C, N)
|
| 243 |
-
c_x = x[start:end]
|
| 244 |
-
c_logits = F.linear(c_x, weight, bias)
|
| 245 |
-
if weight is not None and c_x.dtype != grad_dtype:
|
| 246 |
-
c_x = c_x.to(dtype=grad_dtype)
|
| 247 |
-
c_target = target[start:end]
|
| 248 |
-
c_lse = logsumexp_fwd_npu(c_logits, scale=logit_scale, softcapping=logit_softcapping, dtype=torch.float)
|
| 249 |
-
|
| 250 |
-
c_loss = loss[start:end]
|
| 251 |
-
if use_l2warp:
|
| 252 |
-
c_maxx, c_ids = torch.max(c_logits, -1, keepdim=True)
|
| 253 |
-
|
| 254 |
-
cross_entropy_kernel[(c_logits.shape[0],)](
|
| 255 |
-
logits=c_logits,
|
| 256 |
-
lse=c_lse,
|
| 257 |
-
target=c_target,
|
| 258 |
-
loss=c_loss,
|
| 259 |
-
total=total,
|
| 260 |
-
ignore_index=ignore_index,
|
| 261 |
-
label_smoothing=label_smoothing,
|
| 262 |
-
logit_scale=logit_scale,
|
| 263 |
-
logit_softcapping=softcap_val,
|
| 264 |
-
HAS_SOFTCAPPING=has_softcapping,
|
| 265 |
-
reduction=reduction,
|
| 266 |
-
V=V,
|
| 267 |
-
BV=BV,
|
| 268 |
-
num_warps=STATIC_WARPS,
|
| 269 |
-
)
|
| 270 |
-
if use_l2warp:
|
| 271 |
-
g_logits_l2 = torch.zeros_like(c_logits)
|
| 272 |
-
l2_factor = l2_penalty_factor / N
|
| 273 |
-
penalty_grad = c_maxx * l2_factor
|
| 274 |
-
g_logits_l2.scatter_(-1, c_ids, penalty_grad)
|
| 275 |
-
|
| 276 |
-
if weight is not None:
|
| 277 |
-
torch.addmm(
|
| 278 |
-
input=dw,
|
| 279 |
-
mat1=g_logits_l2.t().to(dtype=grad_dtype),
|
| 280 |
-
mat2=c_x,
|
| 281 |
-
out=dw,
|
| 282 |
-
)
|
| 283 |
-
if bias is not None:
|
| 284 |
-
torch.add(input=db, other=g_logits_l2.sum(0, dtype=bias_grad_dtype), out=db)
|
| 285 |
-
dx_l2_contribution = torch.mm(g_logits_l2, weight)
|
| 286 |
-
else:
|
| 287 |
-
dx_l2_contribution = 0.0
|
| 288 |
-
|
| 289 |
-
c_grad = c_logits if c_logits.is_contiguous() else c_logits.contiguous()
|
| 290 |
-
dx[start:end] = torch.mm(c_grad, weight) + dx_l2_contribution
|
| 291 |
-
|
| 292 |
-
if weight is not None:
|
| 293 |
-
grad_w = c_grad.t().to(dtype=grad_dtype)
|
| 294 |
-
grad_x = c_x if c_x.dtype == grad_dtype else c_x.to(dtype=grad_dtype)
|
| 295 |
-
dw.add_(grad_w @ grad_x)
|
| 296 |
-
|
| 297 |
-
if bias is not None:
|
| 298 |
-
torch.add(input=db, other=c_logits.sum(0, dtype=bias_grad_dtype), out=db)
|
| 299 |
-
|
| 300 |
-
loss = loss.sum()
|
| 301 |
-
if dw is not None:
|
| 302 |
-
dw = dw.to(weight)
|
| 303 |
-
if db is not None:
|
| 304 |
-
db = db.to(bias)
|
| 305 |
-
return loss, dx, dw, db
|
| 306 |
-
|
| 307 |
-
|
| 308 |
-
def fused_linear_cross_entropy_backward_npu(
|
| 309 |
-
do: torch.Tensor,
|
| 310 |
-
dx: torch.Tensor,
|
| 311 |
-
dw: torch.Tensor,
|
| 312 |
-
db: torch.Tensor,
|
| 313 |
-
):
|
| 314 |
-
if torch.ne(do, torch.tensor(1.0, device=do.device)):
|
| 315 |
-
N, H = dx.shape
|
| 316 |
-
B = compute_elementwise_block_size(N * H, _ELEMENTWISE_MEM_MULT)
|
| 317 |
-
|
| 318 |
-
elementwise_mul_kernel[(triton.cdiv(N * H, B),)](
|
| 319 |
-
x=dx,
|
| 320 |
-
g=do,
|
| 321 |
-
N=N*H,
|
| 322 |
-
B=B,
|
| 323 |
-
num_warps=STATIC_WARPS,
|
| 324 |
-
)
|
| 325 |
-
|
| 326 |
-
if dw is not None:
|
| 327 |
-
V, H = dw.shape
|
| 328 |
-
B_dw = compute_elementwise_block_size(V * H, _ELEMENTWISE_MEM_MULT)
|
| 329 |
-
elementwise_mul_kernel[(triton.cdiv(V * H, B_dw),)](
|
| 330 |
-
x=dw,
|
| 331 |
-
g=do,
|
| 332 |
-
N=V*H,
|
| 333 |
-
B=B_dw,
|
| 334 |
-
num_warps=STATIC_WARPS,
|
| 335 |
-
)
|
| 336 |
-
|
| 337 |
-
if db is not None:
|
| 338 |
-
V = db.shape[0]
|
| 339 |
-
B_db = compute_elementwise_block_size(V, _ELEMENTWISE_MEM_MULT)
|
| 340 |
-
elementwise_mul_kernel[(triton.cdiv(V, B_db),)](
|
| 341 |
-
x=db,
|
| 342 |
-
g=do,
|
| 343 |
-
N=V,
|
| 344 |
-
B=B_db,
|
| 345 |
-
num_warps=STATIC_WARPS,
|
| 346 |
-
)
|
| 347 |
-
return dx, dw, db
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
build/torch-cuda/modules/backends/triton_ascend/grpo.py
DELETED
|
@@ -1,266 +0,0 @@
|
|
| 1 |
-
# Copyright (c) 2023-2026, Songlin Yang, Yu Zhang, Zhiyuan Li
|
| 2 |
-
#
|
| 3 |
-
# This source code is licensed under the MIT license found in the
|
| 4 |
-
# LICENSE file in the root directory of this source tree.
|
| 5 |
-
# For a list of all contributors, visit:
|
| 6 |
-
# https://github.com/fla-org/flash-linear-attention/graphs/contributors
|
| 7 |
-
|
| 8 |
-
"""GRPO loss kernels adapted for triton-ascend on Huawei NPU."""
|
| 9 |
-
|
| 10 |
-
import torch
|
| 11 |
-
import triton
|
| 12 |
-
import triton.language as tl
|
| 13 |
-
|
| 14 |
-
from ....ops.utils.op import exp, log
|
| 15 |
-
from ....utils import input_guard
|
| 16 |
-
from ....utils.ascend_ub_manager import ASCEND_MAX_GRID_DIM, compute_vocab_block_size, iter_axis_launch_chunks
|
| 17 |
-
|
| 18 |
-
# GRPO: use conservative multiplier covering both fwd softmax and bwd grad paths.
|
| 19 |
-
_GRPO_MEM_MULT = 8.0
|
| 20 |
-
STATIC_WARPS = 2
|
| 21 |
-
|
| 22 |
-
|
| 23 |
-
def _npu_vocab_block_size(vocab_size: int, num_rows: int) -> int:
|
| 24 |
-
return compute_vocab_block_size(vocab_size, num_rows, _GRPO_MEM_MULT)
|
| 25 |
-
|
| 26 |
-
|
| 27 |
-
@triton.jit
|
| 28 |
-
def grpo_fwd_kernel(
|
| 29 |
-
logits_ptr,
|
| 30 |
-
ref_logp_ptr,
|
| 31 |
-
input_ids_ptr,
|
| 32 |
-
advantages_ptr,
|
| 33 |
-
completion_mask_ptr,
|
| 34 |
-
loss_ptr,
|
| 35 |
-
lse_ptr,
|
| 36 |
-
beta,
|
| 37 |
-
save_kl: tl.constexpr,
|
| 38 |
-
B,
|
| 39 |
-
M,
|
| 40 |
-
N,
|
| 41 |
-
L,
|
| 42 |
-
start_idx,
|
| 43 |
-
BLOCK_SIZE: tl.constexpr,
|
| 44 |
-
ROW_OFFSET: tl.constexpr,
|
| 45 |
-
):
|
| 46 |
-
row_idx = tl.program_id(0) + ROW_OFFSET
|
| 47 |
-
|
| 48 |
-
off_b = row_idx // L
|
| 49 |
-
N = tl.cast(N, tl.int64)
|
| 50 |
-
|
| 51 |
-
loss_ptr += row_idx
|
| 52 |
-
|
| 53 |
-
completion_mask_ptr += row_idx
|
| 54 |
-
not_skip = tl.load(completion_mask_ptr).to(tl.int1)
|
| 55 |
-
if not_skip == 1:
|
| 56 |
-
ref_logp_ptr += row_idx
|
| 57 |
-
lse_ptr += row_idx
|
| 58 |
-
advantages_ptr += off_b
|
| 59 |
-
logits_ptr += N * (row_idx + off_b)
|
| 60 |
-
input_ids_ptr += row_idx + (off_b + 1) * start_idx
|
| 61 |
-
base_cols = tl.arange(0, BLOCK_SIZE)
|
| 62 |
-
|
| 63 |
-
m_i = -float("inf")
|
| 64 |
-
l_i = 0.0
|
| 65 |
-
for start_n in tl.range(0, N, BLOCK_SIZE):
|
| 66 |
-
cols = start_n + base_cols
|
| 67 |
-
mask = cols < N
|
| 68 |
-
logits = tl.load(logits_ptr + cols, mask=mask, other=-float('inf')).to(tl.float32)
|
| 69 |
-
m_ij = tl.max(logits)
|
| 70 |
-
new_m_i = tl.maximum(m_i, m_ij)
|
| 71 |
-
l_i = l_i * exp(m_i - new_m_i) + tl.sum(exp(logits - new_m_i))
|
| 72 |
-
m_i = new_m_i
|
| 73 |
-
lse = log(l_i) + m_i
|
| 74 |
-
|
| 75 |
-
idx = tl.load(input_ids_ptr)
|
| 76 |
-
x = tl.load(logits_ptr + idx).to(tl.float32)
|
| 77 |
-
advantage = tl.load(advantages_ptr).to(tl.float32)
|
| 78 |
-
ref_logp = tl.load(ref_logp_ptr)
|
| 79 |
-
logp = x - lse
|
| 80 |
-
diff = ref_logp - logp
|
| 81 |
-
kl = exp(diff) - diff - 1
|
| 82 |
-
loss = kl * beta - advantage
|
| 83 |
-
|
| 84 |
-
tl.store(loss_ptr, loss.to(loss_ptr.dtype.element_ty))
|
| 85 |
-
tl.store(lse_ptr, lse.to(lse_ptr.dtype.element_ty))
|
| 86 |
-
if save_kl:
|
| 87 |
-
tl.store(loss_ptr + M, kl.to(loss_ptr.dtype.element_ty))
|
| 88 |
-
else:
|
| 89 |
-
tl.store(loss_ptr, 0.0)
|
| 90 |
-
if save_kl:
|
| 91 |
-
tl.store(loss_ptr + M, 0.0)
|
| 92 |
-
|
| 93 |
-
|
| 94 |
-
@triton.jit
|
| 95 |
-
def grpo_bwd_kernel(
|
| 96 |
-
dloss_ptr,
|
| 97 |
-
dlogits_ptr,
|
| 98 |
-
logits_ptr,
|
| 99 |
-
ref_logp_ptr,
|
| 100 |
-
input_ids_ptr,
|
| 101 |
-
advantages_ptr,
|
| 102 |
-
completion_mask_ptr,
|
| 103 |
-
lse_ptr,
|
| 104 |
-
beta,
|
| 105 |
-
B,
|
| 106 |
-
N,
|
| 107 |
-
L,
|
| 108 |
-
start_idx,
|
| 109 |
-
BLOCK_SIZE: tl.constexpr,
|
| 110 |
-
ROW_OFFSET: tl.constexpr,
|
| 111 |
-
):
|
| 112 |
-
row_idx = tl.program_id(0) + ROW_OFFSET
|
| 113 |
-
off_b = row_idx // L
|
| 114 |
-
|
| 115 |
-
N = tl.cast(N, tl.int64)
|
| 116 |
-
|
| 117 |
-
dlogits_ptr += N * (row_idx + off_b)
|
| 118 |
-
base_cols = tl.arange(0, BLOCK_SIZE)
|
| 119 |
-
completion_mask_ptr += row_idx
|
| 120 |
-
not_skip = tl.load(completion_mask_ptr).to(tl.int1)
|
| 121 |
-
|
| 122 |
-
if not_skip == 1:
|
| 123 |
-
lse_ptr += row_idx
|
| 124 |
-
dloss_ptr += row_idx
|
| 125 |
-
advantages_ptr += off_b
|
| 126 |
-
ref_logp_ptr += row_idx
|
| 127 |
-
logits_ptr += N * (row_idx + off_b)
|
| 128 |
-
input_ids_ptr += row_idx + (off_b + 1) * start_idx
|
| 129 |
-
dloss = tl.load(dloss_ptr).to(tl.float32)
|
| 130 |
-
lse = tl.load(lse_ptr).to(tl.float32)
|
| 131 |
-
idx = tl.load(input_ids_ptr)
|
| 132 |
-
x = tl.load(logits_ptr + idx).to(tl.float32)
|
| 133 |
-
advantage = tl.load(advantages_ptr).to(tl.float32)
|
| 134 |
-
ref_logp = tl.load(ref_logp_ptr)
|
| 135 |
-
logp = x - lse
|
| 136 |
-
|
| 137 |
-
dlogp = (beta * (-1.0 * exp(ref_logp - logp) + 1) - advantage) * dloss
|
| 138 |
-
|
| 139 |
-
for start_n in tl.range(0, N, BLOCK_SIZE):
|
| 140 |
-
cols = start_n + base_cols
|
| 141 |
-
mask = cols < N
|
| 142 |
-
logits = tl.load(logits_ptr + cols, mask=mask, other=-float('inf')).to(tl.float32)
|
| 143 |
-
probs = exp(logits - lse)
|
| 144 |
-
dlogits = tl.where(cols == idx, 1 - probs, -probs) * dlogp
|
| 145 |
-
|
| 146 |
-
tl.store(dlogits_ptr + cols, dlogits.to(dlogits_ptr.dtype.element_ty), mask=mask)
|
| 147 |
-
else:
|
| 148 |
-
dlogits = tl.zeros((BLOCK_SIZE,), dtype=tl.float32)
|
| 149 |
-
for start_n in tl.range(0, N, BLOCK_SIZE):
|
| 150 |
-
cols = start_n + base_cols
|
| 151 |
-
mask = cols < N
|
| 152 |
-
|
| 153 |
-
tl.store(dlogits_ptr + cols, dlogits.to(dlogits_ptr.dtype.element_ty), mask=mask)
|
| 154 |
-
|
| 155 |
-
|
| 156 |
-
class GrpoLossNPU(torch.autograd.Function):
|
| 157 |
-
|
| 158 |
-
@input_guard
|
| 159 |
-
@staticmethod
|
| 160 |
-
def forward(ctx, logits, ref_logp, input_ids, advantages, beta, completion_mask, save_kl, inplace=True):
|
| 161 |
-
ctx.input_shape = logits.shape
|
| 162 |
-
B, L_ADD_1, N = ctx.input_shape
|
| 163 |
-
L = L_ADD_1 - 1
|
| 164 |
-
M = B * L
|
| 165 |
-
input_ids_start_index = input_ids.size(1) - L
|
| 166 |
-
block_size = _npu_vocab_block_size(N, M)
|
| 167 |
-
|
| 168 |
-
if not save_kl:
|
| 169 |
-
loss = torch.empty(B, L, device=logits.device, dtype=torch.float32)
|
| 170 |
-
else:
|
| 171 |
-
loss = torch.empty(B * 2, L, device=logits.device, dtype=torch.float32)
|
| 172 |
-
|
| 173 |
-
lse = torch.empty(B, L, device=logits.device, dtype=torch.float32)
|
| 174 |
-
|
| 175 |
-
if completion_mask is None:
|
| 176 |
-
completion_mask = torch.ones(B, L, device=logits.device, dtype=torch.int32)
|
| 177 |
-
else:
|
| 178 |
-
loss[:B].masked_fill_(completion_mask.logical_not(), 0.0)
|
| 179 |
-
|
| 180 |
-
for row_off, row_len in iter_axis_launch_chunks(M, 1, max_grid=ASCEND_MAX_GRID_DIM):
|
| 181 |
-
grpo_fwd_kernel[(row_len,)](
|
| 182 |
-
logits_ptr=logits,
|
| 183 |
-
ref_logp_ptr=ref_logp,
|
| 184 |
-
input_ids_ptr=input_ids,
|
| 185 |
-
advantages_ptr=advantages,
|
| 186 |
-
completion_mask_ptr=completion_mask,
|
| 187 |
-
loss_ptr=loss,
|
| 188 |
-
lse_ptr=lse,
|
| 189 |
-
beta=beta,
|
| 190 |
-
save_kl=save_kl,
|
| 191 |
-
B=B,
|
| 192 |
-
M=M,
|
| 193 |
-
N=N,
|
| 194 |
-
L=L,
|
| 195 |
-
start_idx=input_ids_start_index,
|
| 196 |
-
BLOCK_SIZE=block_size,
|
| 197 |
-
ROW_OFFSET=row_off,
|
| 198 |
-
num_warps=STATIC_WARPS,
|
| 199 |
-
)
|
| 200 |
-
ctx.beta = beta
|
| 201 |
-
ctx.save_for_backward(lse, logits, input_ids, advantages, completion_mask)
|
| 202 |
-
ctx.ref_logp = ref_logp
|
| 203 |
-
ctx.inplace = inplace
|
| 204 |
-
ctx.block_size = block_size
|
| 205 |
-
return loss
|
| 206 |
-
|
| 207 |
-
@input_guard
|
| 208 |
-
@staticmethod
|
| 209 |
-
def backward(ctx, dloss):
|
| 210 |
-
lse, logits, input_ids, advantages, completion_mask = ctx.saved_tensors
|
| 211 |
-
inplace = ctx.inplace
|
| 212 |
-
B, L_ADD_1, N = ctx.input_shape
|
| 213 |
-
L = L_ADD_1 - 1
|
| 214 |
-
M = B * L
|
| 215 |
-
block_size = ctx.block_size
|
| 216 |
-
|
| 217 |
-
input_ids_start_index = input_ids.size(1) - L
|
| 218 |
-
|
| 219 |
-
dlogits = logits if inplace else torch.empty_like(logits)
|
| 220 |
-
|
| 221 |
-
for row_off, row_len in iter_axis_launch_chunks(M, 1, max_grid=ASCEND_MAX_GRID_DIM):
|
| 222 |
-
grpo_bwd_kernel[(row_len,)](
|
| 223 |
-
dloss_ptr=dloss,
|
| 224 |
-
dlogits_ptr=dlogits,
|
| 225 |
-
logits_ptr=logits,
|
| 226 |
-
ref_logp_ptr=ctx.ref_logp,
|
| 227 |
-
input_ids_ptr=input_ids,
|
| 228 |
-
advantages_ptr=advantages,
|
| 229 |
-
completion_mask_ptr=completion_mask,
|
| 230 |
-
lse_ptr=lse,
|
| 231 |
-
beta=ctx.beta,
|
| 232 |
-
B=B,
|
| 233 |
-
N=N,
|
| 234 |
-
L=L,
|
| 235 |
-
BLOCK_SIZE=block_size,
|
| 236 |
-
start_idx=input_ids_start_index,
|
| 237 |
-
ROW_OFFSET=row_off,
|
| 238 |
-
num_warps=STATIC_WARPS,
|
| 239 |
-
)
|
| 240 |
-
dlogits[:, -1, :].fill_(0.0)
|
| 241 |
-
return dlogits.view(*ctx.input_shape), None, None, None, None, None, None, None
|
| 242 |
-
|
| 243 |
-
|
| 244 |
-
def fused_grpo_loss_npu(
|
| 245 |
-
logits,
|
| 246 |
-
ref_logp,
|
| 247 |
-
input_ids,
|
| 248 |
-
advantages,
|
| 249 |
-
beta=0.1,
|
| 250 |
-
completion_mask=None,
|
| 251 |
-
save_kl=False,
|
| 252 |
-
inplace=False,
|
| 253 |
-
) -> torch.Tensor:
|
| 254 |
-
out = GrpoLossNPU.apply(
|
| 255 |
-
logits,
|
| 256 |
-
ref_logp,
|
| 257 |
-
input_ids,
|
| 258 |
-
advantages,
|
| 259 |
-
beta,
|
| 260 |
-
completion_mask,
|
| 261 |
-
save_kl,
|
| 262 |
-
inplace,
|
| 263 |
-
)
|
| 264 |
-
if not save_kl:
|
| 265 |
-
return out
|
| 266 |
-
return out.chunk(2, axis=0)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
build/torch-cuda/modules/backends/triton_ascend/layernorm.py
DELETED
|
@@ -1,355 +0,0 @@
|
|
| 1 |
-
# Copyright (c) 2023-2026, Songlin Yang, Yu Zhang, Zhiyuan Li
|
| 2 |
-
#
|
| 3 |
-
# This source code is licensed under the MIT license found in the
|
| 4 |
-
# LICENSE file in the root directory of this source tree.
|
| 5 |
-
# For a list of all contributors, visit:
|
| 6 |
-
# https://github.com/fla-org/flash-linear-attention/graphs/contributors
|
| 7 |
-
|
| 8 |
-
"""LayerNorm / RMSNorm / GroupNorm kernels adapted for triton-ascend on Huawei NPU."""
|
| 9 |
-
|
| 10 |
-
import torch
|
| 11 |
-
import triton
|
| 12 |
-
import triton.language as tl
|
| 13 |
-
|
| 14 |
-
from ....utils import get_multiprocessor_count
|
| 15 |
-
from ....utils.ascend_ub_manager import ASCEND_MAX_GRID_DIM, compute_ub_block_size, iter_axis_launch_chunks
|
| 16 |
-
|
| 17 |
-
# Peak live fp32 vectors in row-wise kernel1 (see Liger Ascend layer_norm).
|
| 18 |
-
_FWD_MEM_MULT = 6.0
|
| 19 |
-
_BWD_MEM_MULT = 8.0
|
| 20 |
-
_UB_SAFETY_MARGIN = 0.85
|
| 21 |
-
# Legacy byte cap when UB capacity cannot be detected (65536 // fp32).
|
| 22 |
-
_FALLBACK_MAX_BD = 65536 // 4
|
| 23 |
-
|
| 24 |
-
|
| 25 |
-
def _get_layer_norm_bd(D: int, is_forward: bool) -> int:
|
| 26 |
-
"""Return power-of-2 block size for feature dim D under UB constraints."""
|
| 27 |
-
memory_multiplier = _FWD_MEM_MULT if is_forward else _BWD_MEM_MULT
|
| 28 |
-
return compute_ub_block_size(
|
| 29 |
-
D,
|
| 30 |
-
memory_multiplier,
|
| 31 |
-
safety_margin=_UB_SAFETY_MARGIN,
|
| 32 |
-
fallback=_FALLBACK_MAX_BD,
|
| 33 |
-
desired=triton.next_power_of_2(D),
|
| 34 |
-
)
|
| 35 |
-
|
| 36 |
-
|
| 37 |
-
def _layer_norm_bwd_launch_config(T: int, G: int, device_index: int) -> tuple[int, int, int]:
|
| 38 |
-
"""Return (NS, BS, GS) capped under Ascend grid limit."""
|
| 39 |
-
NS = min(triton.cdiv(get_multiprocessor_count(device_index), G), T // G) * G
|
| 40 |
-
NS = min(NS, ASCEND_MAX_GRID_DIM)
|
| 41 |
-
BS = triton.cdiv(T, NS) if NS > 0 else T
|
| 42 |
-
GS = NS // G if G > 0 else NS
|
| 43 |
-
return NS, BS, GS
|
| 44 |
-
|
| 45 |
-
|
| 46 |
-
@triton.jit
|
| 47 |
-
def layer_norm_fwd_kernel1(
|
| 48 |
-
x,
|
| 49 |
-
y,
|
| 50 |
-
w,
|
| 51 |
-
b,
|
| 52 |
-
res,
|
| 53 |
-
res_out,
|
| 54 |
-
mean,
|
| 55 |
-
rstd,
|
| 56 |
-
eps,
|
| 57 |
-
G: tl.constexpr,
|
| 58 |
-
D: tl.constexpr,
|
| 59 |
-
BD: tl.constexpr,
|
| 60 |
-
IS_RMS_NORM: tl.constexpr,
|
| 61 |
-
HAS_RESIDUAL: tl.constexpr,
|
| 62 |
-
STORE_RESIDUAL_OUT: tl.constexpr,
|
| 63 |
-
HAS_WEIGHT: tl.constexpr,
|
| 64 |
-
HAS_BIAS: tl.constexpr,
|
| 65 |
-
):
|
| 66 |
-
i_t = tl.program_id(0)
|
| 67 |
-
i_g = i_t % G
|
| 68 |
-
|
| 69 |
-
x += i_t * D
|
| 70 |
-
y += i_t * D
|
| 71 |
-
if HAS_RESIDUAL:
|
| 72 |
-
res += i_t * D
|
| 73 |
-
if STORE_RESIDUAL_OUT:
|
| 74 |
-
res_out += i_t * D
|
| 75 |
-
|
| 76 |
-
o_d = tl.arange(0, BD)
|
| 77 |
-
m_d = o_d < D
|
| 78 |
-
b_x = tl.load(x + o_d, mask=m_d, other=0.0).to(tl.float32)
|
| 79 |
-
if HAS_RESIDUAL:
|
| 80 |
-
b_x += tl.load(res + o_d, mask=m_d, other=0.0).to(tl.float32)
|
| 81 |
-
if STORE_RESIDUAL_OUT:
|
| 82 |
-
tl.store(res_out + o_d, b_x, mask=m_d)
|
| 83 |
-
if not IS_RMS_NORM:
|
| 84 |
-
b_mean = tl.sum(b_x, axis=0) / D
|
| 85 |
-
tl.store(mean + i_t, b_mean)
|
| 86 |
-
b_xbar = tl.where(m_d, b_x - b_mean, 0.0)
|
| 87 |
-
b_var = tl.sum(b_xbar * b_xbar, axis=0) / D
|
| 88 |
-
else:
|
| 89 |
-
b_xbar = tl.where(m_d, b_x, 0.0)
|
| 90 |
-
b_var = tl.sum(b_xbar * b_xbar, axis=0) / D
|
| 91 |
-
b_rstd = 1 / tl.sqrt(b_var + eps)
|
| 92 |
-
tl.store(rstd + i_t, b_rstd)
|
| 93 |
-
|
| 94 |
-
if HAS_WEIGHT:
|
| 95 |
-
b_w = tl.load(w + i_g * D + o_d, mask=m_d).to(tl.float32)
|
| 96 |
-
if HAS_BIAS:
|
| 97 |
-
b_b = tl.load(b + i_g * D + o_d, mask=m_d).to(tl.float32)
|
| 98 |
-
b_x_hat = (b_x - b_mean) * b_rstd if not IS_RMS_NORM else b_x * b_rstd
|
| 99 |
-
b_y = b_x_hat * b_w if HAS_WEIGHT else b_x_hat
|
| 100 |
-
if HAS_BIAS:
|
| 101 |
-
b_y = b_y + b_b
|
| 102 |
-
|
| 103 |
-
tl.store(y + o_d, b_y, mask=m_d)
|
| 104 |
-
|
| 105 |
-
|
| 106 |
-
@triton.heuristics({
|
| 107 |
-
'RECOMPUTE_OUTPUT': lambda args: args['y'] is not None,
|
| 108 |
-
})
|
| 109 |
-
@triton.jit
|
| 110 |
-
def layer_norm_bwd_kernel1(
|
| 111 |
-
x,
|
| 112 |
-
w,
|
| 113 |
-
b,
|
| 114 |
-
y,
|
| 115 |
-
dy,
|
| 116 |
-
dx,
|
| 117 |
-
dw,
|
| 118 |
-
db,
|
| 119 |
-
dres,
|
| 120 |
-
dres_in,
|
| 121 |
-
mean,
|
| 122 |
-
rstd,
|
| 123 |
-
T,
|
| 124 |
-
G: tl.constexpr,
|
| 125 |
-
D: tl.constexpr,
|
| 126 |
-
BS: tl.constexpr,
|
| 127 |
-
BD: tl.constexpr,
|
| 128 |
-
GS: tl.constexpr,
|
| 129 |
-
IS_RMS_NORM: tl.constexpr,
|
| 130 |
-
HAS_DRESIDUAL: tl.constexpr,
|
| 131 |
-
STORE_DRESIDUAL: tl.constexpr,
|
| 132 |
-
HAS_WEIGHT: tl.constexpr,
|
| 133 |
-
HAS_BIAS: tl.constexpr,
|
| 134 |
-
RECOMPUTE_OUTPUT: tl.constexpr,
|
| 135 |
-
):
|
| 136 |
-
i_s = tl.program_id(0)
|
| 137 |
-
i_g, i_sg = i_s // GS, i_s % GS
|
| 138 |
-
|
| 139 |
-
o_d = tl.arange(0, BD)
|
| 140 |
-
mask = o_d < D
|
| 141 |
-
|
| 142 |
-
if HAS_WEIGHT:
|
| 143 |
-
b_w = tl.load(w + i_g * D + o_d, mask=mask).to(tl.float32)
|
| 144 |
-
b_dw = tl.zeros((BD,), dtype=tl.float32)
|
| 145 |
-
if RECOMPUTE_OUTPUT and HAS_BIAS:
|
| 146 |
-
b_b = tl.load(b + i_g * D + o_d, mask=mask, other=0.0).to(tl.float32)
|
| 147 |
-
if HAS_BIAS:
|
| 148 |
-
b_db = tl.zeros((BD,), dtype=tl.float32)
|
| 149 |
-
|
| 150 |
-
for i_t in range(i_sg * BS * G + i_g, min((i_sg * BS + BS) * G + i_g, T), G):
|
| 151 |
-
b_x = tl.load(x + i_t * D + o_d, mask=mask, other=0).to(tl.float32)
|
| 152 |
-
b_dy = tl.load(dy + i_t * D + o_d, mask=mask, other=0).to(tl.float32)
|
| 153 |
-
|
| 154 |
-
if not IS_RMS_NORM:
|
| 155 |
-
b_mean = tl.load(mean + i_t)
|
| 156 |
-
b_rstd = tl.load(rstd + i_t)
|
| 157 |
-
b_xhat = (b_x - b_mean) * b_rstd if not IS_RMS_NORM else b_x * b_rstd
|
| 158 |
-
b_xhat = tl.where(mask, b_xhat, 0.0)
|
| 159 |
-
if RECOMPUTE_OUTPUT:
|
| 160 |
-
b_y = b_xhat * b_w if HAS_WEIGHT else b_xhat
|
| 161 |
-
if HAS_BIAS:
|
| 162 |
-
b_y = b_y + b_b
|
| 163 |
-
tl.store(y + i_t * D + o_d, b_y, mask=mask)
|
| 164 |
-
b_wdy = b_dy
|
| 165 |
-
if HAS_WEIGHT:
|
| 166 |
-
b_wdy = b_dy * b_w
|
| 167 |
-
b_dw += b_dy * b_xhat
|
| 168 |
-
if HAS_BIAS:
|
| 169 |
-
b_db += b_dy
|
| 170 |
-
if not IS_RMS_NORM:
|
| 171 |
-
b_c1 = tl.sum(b_xhat * b_wdy, axis=0) / D
|
| 172 |
-
b_c2 = tl.sum(b_wdy, axis=0) / D
|
| 173 |
-
b_dx = (b_wdy - (b_xhat * b_c1 + b_c2)) * b_rstd
|
| 174 |
-
else:
|
| 175 |
-
b_c1 = tl.sum(b_xhat * b_wdy, axis=0) / D
|
| 176 |
-
b_dx = (b_wdy - b_xhat * b_c1) * b_rstd
|
| 177 |
-
if HAS_DRESIDUAL:
|
| 178 |
-
b_dres = tl.load(dres + i_t * D + o_d, mask=mask, other=0).to(tl.float32)
|
| 179 |
-
b_dx += b_dres
|
| 180 |
-
b_dx = tl.cast(b_dx, dtype=dx.dtype.element_ty, fp_downcast_rounding='rtne')
|
| 181 |
-
if STORE_DRESIDUAL:
|
| 182 |
-
tl.store(dres_in + i_t * D + o_d, b_dx, mask=mask)
|
| 183 |
-
tl.store(dx + i_t * D + o_d, b_dx, mask=mask)
|
| 184 |
-
|
| 185 |
-
if HAS_WEIGHT:
|
| 186 |
-
tl.store(dw + i_s * D + o_d, b_dw, mask=mask)
|
| 187 |
-
if HAS_BIAS:
|
| 188 |
-
tl.store(db + i_s * D + o_d, b_db, mask=mask)
|
| 189 |
-
|
| 190 |
-
|
| 191 |
-
def _launch_layer_norm_fwd_kernel1(
|
| 192 |
-
x: torch.Tensor,
|
| 193 |
-
y: torch.Tensor,
|
| 194 |
-
weight: torch.Tensor,
|
| 195 |
-
bias: torch.Tensor,
|
| 196 |
-
residual: torch.Tensor,
|
| 197 |
-
res_out: torch.Tensor,
|
| 198 |
-
mean: torch.Tensor,
|
| 199 |
-
rstd: torch.Tensor,
|
| 200 |
-
eps: float,
|
| 201 |
-
G: int,
|
| 202 |
-
D: int,
|
| 203 |
-
BD: int,
|
| 204 |
-
is_rms_norm: bool,
|
| 205 |
-
):
|
| 206 |
-
chunk_T = x.shape[0]
|
| 207 |
-
layer_norm_fwd_kernel1[(chunk_T,)](
|
| 208 |
-
x,
|
| 209 |
-
y,
|
| 210 |
-
weight,
|
| 211 |
-
bias,
|
| 212 |
-
residual,
|
| 213 |
-
res_out,
|
| 214 |
-
mean,
|
| 215 |
-
rstd,
|
| 216 |
-
eps,
|
| 217 |
-
G=G,
|
| 218 |
-
D=D,
|
| 219 |
-
BD=BD,
|
| 220 |
-
IS_RMS_NORM=is_rms_norm,
|
| 221 |
-
HAS_RESIDUAL=residual is not None,
|
| 222 |
-
STORE_RESIDUAL_OUT=res_out is not None,
|
| 223 |
-
HAS_WEIGHT=weight is not None,
|
| 224 |
-
HAS_BIAS=bias is not None,
|
| 225 |
-
)
|
| 226 |
-
|
| 227 |
-
|
| 228 |
-
def layer_norm_fwd_npu(
|
| 229 |
-
x: torch.Tensor,
|
| 230 |
-
weight: torch.Tensor,
|
| 231 |
-
bias: torch.Tensor,
|
| 232 |
-
eps: float = 1e-5,
|
| 233 |
-
residual: torch.Tensor = None,
|
| 234 |
-
out_dtype: torch.dtype = None,
|
| 235 |
-
residual_dtype: torch.dtype = None,
|
| 236 |
-
is_rms_norm: bool = False,
|
| 237 |
-
num_groups: int = 1,
|
| 238 |
-
):
|
| 239 |
-
if residual is not None:
|
| 240 |
-
residual_dtype = residual.dtype
|
| 241 |
-
T, D, G = *x.shape, num_groups
|
| 242 |
-
if residual is not None:
|
| 243 |
-
assert residual.shape == (T, D)
|
| 244 |
-
if weight is not None:
|
| 245 |
-
assert weight.shape == (G * D,)
|
| 246 |
-
if bias is not None:
|
| 247 |
-
assert bias.shape == (G * D,)
|
| 248 |
-
|
| 249 |
-
y = torch.empty_like(x, dtype=x.dtype if out_dtype is None else out_dtype)
|
| 250 |
-
if residual is not None or (residual_dtype is not None and residual_dtype != x.dtype):
|
| 251 |
-
res_out = torch.empty(T, D, device=x.device, dtype=residual_dtype)
|
| 252 |
-
else:
|
| 253 |
-
res_out = None
|
| 254 |
-
mean = torch.empty((T,), dtype=torch.float, device=x.device) if not is_rms_norm else None
|
| 255 |
-
rstd = torch.empty((T,), dtype=torch.float, device=x.device)
|
| 256 |
-
|
| 257 |
-
BD = _get_layer_norm_bd(D, is_forward=True)
|
| 258 |
-
if D > BD:
|
| 259 |
-
raise RuntimeError(
|
| 260 |
-
f"LayerNorm feature dim {D} exceeds UB-safe block size {BD}. "
|
| 261 |
-
"Column-tiled kernels are not yet implemented for this size."
|
| 262 |
-
)
|
| 263 |
-
|
| 264 |
-
# Ascend: use row-wise kernel1 (no make_block_ptr) for all feature dims.
|
| 265 |
-
# Split along rows when T exceeds the Ascend grid limit.
|
| 266 |
-
for row_start, row_len in iter_axis_launch_chunks(T, 1, max_grid=ASCEND_MAX_GRID_DIM):
|
| 267 |
-
row_end = row_start + row_len
|
| 268 |
-
_launch_layer_norm_fwd_kernel1(
|
| 269 |
-
x[row_start:row_end],
|
| 270 |
-
y[row_start:row_end],
|
| 271 |
-
weight,
|
| 272 |
-
bias,
|
| 273 |
-
None if residual is None else residual[row_start:row_end],
|
| 274 |
-
None if res_out is None else res_out[row_start:row_end],
|
| 275 |
-
None if mean is None else mean[row_start:row_end],
|
| 276 |
-
rstd[row_start:row_end],
|
| 277 |
-
eps,
|
| 278 |
-
G,
|
| 279 |
-
D,
|
| 280 |
-
BD,
|
| 281 |
-
is_rms_norm,
|
| 282 |
-
)
|
| 283 |
-
return y, mean, rstd, res_out if res_out is not None else x
|
| 284 |
-
|
| 285 |
-
|
| 286 |
-
def layer_norm_bwd_npu(
|
| 287 |
-
dy: torch.Tensor,
|
| 288 |
-
x: torch.Tensor,
|
| 289 |
-
weight: torch.Tensor,
|
| 290 |
-
bias: torch.Tensor,
|
| 291 |
-
mean: torch.Tensor = None,
|
| 292 |
-
rstd: torch.Tensor = None,
|
| 293 |
-
dres: torch.Tensor = None,
|
| 294 |
-
has_residual: bool = False,
|
| 295 |
-
is_rms_norm: bool = False,
|
| 296 |
-
x_dtype: torch.dtype = None,
|
| 297 |
-
recompute_output: bool = False,
|
| 298 |
-
num_groups: int = 1,
|
| 299 |
-
):
|
| 300 |
-
T, D, G = *x.shape, num_groups
|
| 301 |
-
assert dy.shape == (T, D)
|
| 302 |
-
if dres is not None:
|
| 303 |
-
assert dres.shape == (T, D)
|
| 304 |
-
if weight is not None:
|
| 305 |
-
assert weight.shape == (G * D,)
|
| 306 |
-
if bias is not None:
|
| 307 |
-
assert bias.shape == (G * D,)
|
| 308 |
-
|
| 309 |
-
dx = torch.empty_like(x) if x_dtype is None else torch.empty(T, D, dtype=x_dtype, device=x.device)
|
| 310 |
-
dres_in = torch.empty_like(x) if has_residual and dx.dtype != x.dtype else None
|
| 311 |
-
y = torch.empty(T, D, dtype=dy.dtype, device=dy.device) if recompute_output else None
|
| 312 |
-
|
| 313 |
-
BD = _get_layer_norm_bd(D, is_forward=False)
|
| 314 |
-
if D > BD:
|
| 315 |
-
raise RuntimeError(
|
| 316 |
-
f"LayerNorm feature dim {D} exceeds UB-safe block size {BD}. "
|
| 317 |
-
"Column-tiled kernels are not yet implemented for this size."
|
| 318 |
-
)
|
| 319 |
-
|
| 320 |
-
NS, BS, GS = _layer_norm_bwd_launch_config(T, G, x.device.index)
|
| 321 |
-
|
| 322 |
-
dw = torch.empty((NS, D), dtype=torch.float, device=weight.device) if weight is not None else None
|
| 323 |
-
db = torch.empty((NS, D), dtype=torch.float, device=bias.device) if bias is not None else None
|
| 324 |
-
grid = (NS,)
|
| 325 |
-
|
| 326 |
-
layer_norm_bwd_kernel1[grid](
|
| 327 |
-
x,
|
| 328 |
-
weight,
|
| 329 |
-
bias,
|
| 330 |
-
y,
|
| 331 |
-
dy,
|
| 332 |
-
dx,
|
| 333 |
-
dw,
|
| 334 |
-
db,
|
| 335 |
-
dres,
|
| 336 |
-
dres_in,
|
| 337 |
-
mean,
|
| 338 |
-
rstd,
|
| 339 |
-
T=T,
|
| 340 |
-
G=G,
|
| 341 |
-
D=D,
|
| 342 |
-
BS=BS,
|
| 343 |
-
BD=BD,
|
| 344 |
-
GS=GS,
|
| 345 |
-
IS_RMS_NORM=is_rms_norm,
|
| 346 |
-
HAS_DRESIDUAL=dres is not None,
|
| 347 |
-
STORE_DRESIDUAL=dres_in is not None,
|
| 348 |
-
HAS_WEIGHT=weight is not None,
|
| 349 |
-
HAS_BIAS=bias is not None,
|
| 350 |
-
)
|
| 351 |
-
dw = dw.view(G, -1, D).sum(1).to(weight).view_as(weight) if weight is not None else None
|
| 352 |
-
db = db.view(G, -1, D).sum(1).to(bias).view_as(bias) if bias is not None else None
|
| 353 |
-
if has_residual and dx.dtype == x.dtype:
|
| 354 |
-
dres_in = dx
|
| 355 |
-
return (dx, dw, db, dres_in) if not recompute_output else (dx, dw, db, dres_in, y)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
build/torch-cuda/modules/backends/triton_ascend/rotary.py
DELETED
|
@@ -1,211 +0,0 @@
|
|
| 1 |
-
# Copyright (c) 2023-2026, Songlin Yang, Yu Zhang, Zhiyuan Li
|
| 2 |
-
#
|
| 3 |
-
# This source code is licensed under the MIT license found in the
|
| 4 |
-
# LICENSE file in the root directory of this source tree.
|
| 5 |
-
# For a list of all contributors, visit:
|
| 6 |
-
# https://github.com/fla-org/flash-linear-attention/graphs/contributors
|
| 7 |
-
|
| 8 |
-
"""Rotary embedding kernels adapted for triton-ascend on Huawei NPU."""
|
| 9 |
-
|
| 10 |
-
import torch
|
| 11 |
-
import triton
|
| 12 |
-
import triton.language as tl
|
| 13 |
-
|
| 14 |
-
from ....ops.utils import prepare_chunk_indices
|
| 15 |
-
from ....utils import autotune_cache_kwargs, get_multiprocessor_count
|
| 16 |
-
from ....utils.ascend_ub_manager import (
|
| 17 |
-
ASCEND_MAX_GRID_DIM,
|
| 18 |
-
compute_grid_limited_tile_size,
|
| 19 |
-
compute_row_tile_block_size,
|
| 20 |
-
max_grid_axis_chunks,
|
| 21 |
-
)
|
| 22 |
-
|
| 23 |
-
# Peak live fp32 tiles in rotary kernel: cos, sin, x0, x1, o0, o1.
|
| 24 |
-
_ROTARY_MEM_MULT = 6.0
|
| 25 |
-
_ROTARY_SAFETY_MARGIN = 0.90
|
| 26 |
-
|
| 27 |
-
# Ascend vector UB is small; large num_warps / stages explodes compile-time UB (see bishengir ub overflow).
|
| 28 |
-
NUM_WARPS_AUTOTUNE = [2, 4]
|
| 29 |
-
NUM_STAGES_AUTOTUNE = [1, 2]
|
| 30 |
-
|
| 31 |
-
|
| 32 |
-
@triton.autotune(
|
| 33 |
-
configs=[
|
| 34 |
-
triton.Config({}, num_warps=num_warps, num_stages=num_stages)
|
| 35 |
-
for num_warps in NUM_WARPS_AUTOTUNE
|
| 36 |
-
for num_stages in NUM_STAGES_AUTOTUNE
|
| 37 |
-
],
|
| 38 |
-
key=['B', 'H', 'D', 'INTERLEAVED'],
|
| 39 |
-
**autotune_cache_kwargs,
|
| 40 |
-
)
|
| 41 |
-
@triton.jit(do_not_specialize=['T'])
|
| 42 |
-
def rotary_embedding_kernel(
|
| 43 |
-
x,
|
| 44 |
-
cos,
|
| 45 |
-
sin,
|
| 46 |
-
y,
|
| 47 |
-
cu_seqlens,
|
| 48 |
-
chunk_indices,
|
| 49 |
-
seq_offsets,
|
| 50 |
-
T,
|
| 51 |
-
B: tl.constexpr,
|
| 52 |
-
H: tl.constexpr,
|
| 53 |
-
D: tl.constexpr,
|
| 54 |
-
R: tl.constexpr,
|
| 55 |
-
TR: tl.constexpr,
|
| 56 |
-
BT: tl.constexpr,
|
| 57 |
-
BD: tl.constexpr,
|
| 58 |
-
IS_SEQLEN_OFFSETS_TENSOR: tl.constexpr,
|
| 59 |
-
IS_VARLEN: tl.constexpr,
|
| 60 |
-
INTERLEAVED: tl.constexpr,
|
| 61 |
-
CONJUGATE: tl.constexpr,
|
| 62 |
-
NT_OFFSET: tl.constexpr,
|
| 63 |
-
):
|
| 64 |
-
i_t, i_b, i_h = tl.program_id(0), tl.program_id(1), tl.program_id(2)
|
| 65 |
-
i_t += NT_OFFSET
|
| 66 |
-
|
| 67 |
-
if IS_VARLEN:
|
| 68 |
-
i_n, i_t = tl.load(chunk_indices + i_t * 2).to(tl.int32), tl.load(chunk_indices + i_t * 2 + 1).to(tl.int32)
|
| 69 |
-
bos, eos = tl.load(cu_seqlens + i_n), tl.load(cu_seqlens + i_n + 1)
|
| 70 |
-
T = eos - bos
|
| 71 |
-
x = x + bos * H*D + i_h * D
|
| 72 |
-
y = y + bos * H*D + i_h * D
|
| 73 |
-
else:
|
| 74 |
-
i_n = i_b
|
| 75 |
-
x = x + i_n * T*H*D + i_h * D
|
| 76 |
-
y = y + i_n * T*H*D + i_h * D
|
| 77 |
-
|
| 78 |
-
if i_t * BT >= T:
|
| 79 |
-
return
|
| 80 |
-
|
| 81 |
-
o_t = i_t * BT + tl.arange(0, BT)
|
| 82 |
-
if not IS_SEQLEN_OFFSETS_TENSOR:
|
| 83 |
-
o_cs = o_t + seq_offsets
|
| 84 |
-
else:
|
| 85 |
-
o_cs = o_t + tl.load(seq_offsets + i_n)
|
| 86 |
-
m_t = (o_t >= 0) & (o_t < T) & (o_cs >= 0) & (o_cs < TR)
|
| 87 |
-
|
| 88 |
-
if not INTERLEAVED:
|
| 89 |
-
o_r = tl.arange(0, BD // 2)
|
| 90 |
-
p_x = x + o_t[:, None] * H*D + o_r[None, :]
|
| 91 |
-
p_cos = cos + (o_cs[:, None] * R + o_r[None, :])
|
| 92 |
-
p_sin = sin + (o_cs[:, None] * R + o_r[None, :])
|
| 93 |
-
mask = m_t[:, None] & (o_r < R)[None, :]
|
| 94 |
-
|
| 95 |
-
b_cos = tl.load(p_cos, mask=mask, other=1.0).to(tl.float32)
|
| 96 |
-
b_sin = tl.load(p_sin, mask=mask, other=0.0).to(tl.float32)
|
| 97 |
-
b_x0 = tl.load(p_x, mask=mask, other=0.0).to(tl.float32)
|
| 98 |
-
b_x1 = tl.load(p_x + R, mask=mask, other=0.0).to(tl.float32)
|
| 99 |
-
if CONJUGATE:
|
| 100 |
-
b_sin = -b_sin
|
| 101 |
-
b_o0 = b_x0 * b_cos - b_x1 * b_sin
|
| 102 |
-
b_o1 = b_x0 * b_sin + b_x1 * b_cos
|
| 103 |
-
p_y = y + (o_t[:, None] * H*D + o_r[None, :])
|
| 104 |
-
tl.store(p_y, b_o0, mask=mask)
|
| 105 |
-
tl.store(p_y + R, b_o1, mask=mask)
|
| 106 |
-
else:
|
| 107 |
-
o_d = tl.arange(0, BD)
|
| 108 |
-
o_d_swap = o_d + ((o_d + 1) % 2) * 2 - 1
|
| 109 |
-
o_d_repeat = tl.arange(0, BD) // 2
|
| 110 |
-
p_x0 = x + o_t[:, None] * H*D + o_d[None, :]
|
| 111 |
-
p_x1 = x + o_t[:, None] * H*D + o_d_swap[None, :]
|
| 112 |
-
p_cos = cos + (o_cs[:, None] * R + o_d_repeat[None, :])
|
| 113 |
-
p_sin = sin + (o_cs[:, None] * R + o_d_repeat[None, :])
|
| 114 |
-
mask = m_t[:, None] & (o_d_repeat < R)[None, :]
|
| 115 |
-
|
| 116 |
-
b_cos = tl.load(p_cos, mask=mask, other=1.0).to(tl.float32)
|
| 117 |
-
b_sin = tl.load(p_sin, mask=mask, other=0.0).to(tl.float32)
|
| 118 |
-
b_x0 = tl.load(p_x0, mask=mask, other=0.0).to(tl.float32)
|
| 119 |
-
b_x1 = tl.load(p_x1, mask=mask, other=0.0).to(tl.float32)
|
| 120 |
-
if CONJUGATE:
|
| 121 |
-
b_sin = -b_sin
|
| 122 |
-
b_o0 = b_x0 * b_cos
|
| 123 |
-
b_o1 = b_x1 * b_sin
|
| 124 |
-
b_y = tl.where(o_d[None, :] % 2 == 0, b_o0 - b_o1, b_o0 + b_o1)
|
| 125 |
-
p_y = y + (o_t[:, None] * H*D + o_d[None, :])
|
| 126 |
-
tl.store(p_y, b_y, mask=mask)
|
| 127 |
-
|
| 128 |
-
|
| 129 |
-
def rotary_embedding_fwdbwd_npu(
|
| 130 |
-
x: torch.Tensor,
|
| 131 |
-
cos: torch.Tensor,
|
| 132 |
-
sin: torch.Tensor,
|
| 133 |
-
seqlen_offsets: int | torch.Tensor = 0,
|
| 134 |
-
cu_seqlens: torch.Tensor | None = None,
|
| 135 |
-
interleaved: bool = False,
|
| 136 |
-
inplace: bool = False,
|
| 137 |
-
conjugate: bool = False,
|
| 138 |
-
chunk_indices: torch.LongTensor | None = None,
|
| 139 |
-
) -> torch.Tensor:
|
| 140 |
-
is_varlen = cu_seqlens is not None
|
| 141 |
-
|
| 142 |
-
B, T, H, D = x.shape
|
| 143 |
-
N = B if not is_varlen else cu_seqlens.shape[0] - 1
|
| 144 |
-
TR, R = cos.shape
|
| 145 |
-
R2 = R * 2
|
| 146 |
-
|
| 147 |
-
assert D <= 256, "Only support D <= 256"
|
| 148 |
-
assert TR >= T, f"TR must be >= T, got {TR} and {T}"
|
| 149 |
-
|
| 150 |
-
assert cos.dtype == sin.dtype, f"cos and sin must have the same dtype, got {cos.dtype} and {sin.dtype}"
|
| 151 |
-
assert x.dtype == cos.dtype, f"Input and cos/sin must have the same dtype, got {x.dtype} and {cos.dtype}"
|
| 152 |
-
|
| 153 |
-
if isinstance(seqlen_offsets, torch.Tensor):
|
| 154 |
-
assert seqlen_offsets.shape == (N,)
|
| 155 |
-
assert seqlen_offsets.dtype in [torch.int32, torch.int64]
|
| 156 |
-
else:
|
| 157 |
-
assert seqlen_offsets + T <= TR
|
| 158 |
-
|
| 159 |
-
y = torch.zeros_like(x) if not inplace else x
|
| 160 |
-
if R2 < D and not inplace:
|
| 161 |
-
y[..., R2:].copy_(x[..., R2:])
|
| 162 |
-
|
| 163 |
-
BD = triton.next_power_of_2(R2)
|
| 164 |
-
desired_bt = triton.next_power_of_2(triton.cdiv(T, get_multiprocessor_count(x.device.index)))
|
| 165 |
-
bt_cap = compute_row_tile_block_size(
|
| 166 |
-
desired_bt,
|
| 167 |
-
R2,
|
| 168 |
-
_ROTARY_MEM_MULT,
|
| 169 |
-
safety_margin=_ROTARY_SAFETY_MARGIN,
|
| 170 |
-
dtype_size=x.element_size(),
|
| 171 |
-
fallback=16 if R >= 128 else (32 if R >= 64 else 64),
|
| 172 |
-
min_block=1,
|
| 173 |
-
)
|
| 174 |
-
BT = min(bt_cap, desired_bt)
|
| 175 |
-
BT = compute_grid_limited_tile_size(T, B * H, BT, max_grid=ASCEND_MAX_GRID_DIM)
|
| 176 |
-
if chunk_indices is None and is_varlen:
|
| 177 |
-
chunk_indices = prepare_chunk_indices(cu_seqlens, BT)
|
| 178 |
-
NT = len(chunk_indices) if is_varlen else triton.cdiv(T, BT)
|
| 179 |
-
|
| 180 |
-
kernel_kwargs = dict(
|
| 181 |
-
x=x,
|
| 182 |
-
cos=cos,
|
| 183 |
-
sin=sin,
|
| 184 |
-
y=y,
|
| 185 |
-
cu_seqlens=cu_seqlens,
|
| 186 |
-
chunk_indices=chunk_indices,
|
| 187 |
-
seq_offsets=seqlen_offsets,
|
| 188 |
-
B=B,
|
| 189 |
-
T=T,
|
| 190 |
-
H=H,
|
| 191 |
-
D=D,
|
| 192 |
-
R=R,
|
| 193 |
-
TR=TR,
|
| 194 |
-
BT=BT,
|
| 195 |
-
BD=BD,
|
| 196 |
-
IS_SEQLEN_OFFSETS_TENSOR=isinstance(seqlen_offsets, torch.Tensor),
|
| 197 |
-
IS_VARLEN=is_varlen,
|
| 198 |
-
INTERLEAVED=interleaved,
|
| 199 |
-
CONJUGATE=conjugate,
|
| 200 |
-
)
|
| 201 |
-
max_nt = max_grid_axis_chunks(NT, B * H, max_grid=ASCEND_MAX_GRID_DIM)
|
| 202 |
-
for nt_off in range(0, NT, max_nt):
|
| 203 |
-
nt_len = min(max_nt, NT - nt_off)
|
| 204 |
-
if is_varlen:
|
| 205 |
-
kernel_kwargs['chunk_indices'] = chunk_indices[nt_off:nt_off + nt_len]
|
| 206 |
-
kernel_kwargs['NT_OFFSET'] = 0
|
| 207 |
-
else:
|
| 208 |
-
kernel_kwargs['chunk_indices'] = chunk_indices
|
| 209 |
-
kernel_kwargs['NT_OFFSET'] = nt_off
|
| 210 |
-
rotary_embedding_kernel[(nt_len, B, H)](**kernel_kwargs)
|
| 211 |
-
return y
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
build/{torch-xpu/modules/conv/triton → torch-cuda/modules/causal_conv1d}/__init__.py
RENAMED
|
@@ -5,20 +5,27 @@
|
|
| 5 |
# For a list of all contributors, visit:
|
| 6 |
# https://github.com/fla-org/flash-linear-attention/graphs/contributors
|
| 7 |
|
| 8 |
-
from .
|
|
|
|
| 9 |
CausalConv1dFunction,
|
|
|
|
|
|
|
| 10 |
causal_conv1d_bwd,
|
| 11 |
causal_conv1d_fwd,
|
| 12 |
causal_conv1d_update,
|
| 13 |
causal_conv1d_update_states,
|
| 14 |
-
compute_dh0_triton,
|
| 15 |
)
|
| 16 |
|
| 17 |
__all__ = [
|
| 18 |
'CausalConv1dFunction',
|
|
|
|
|
|
|
| 19 |
'causal_conv1d_bwd',
|
| 20 |
'causal_conv1d_fwd',
|
| 21 |
'causal_conv1d_update',
|
| 22 |
'causal_conv1d_update_states',
|
| 23 |
-
'compute_dh0_triton',
|
| 24 |
]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 5 |
# For a list of all contributors, visit:
|
| 6 |
# https://github.com/fla-org/flash-linear-attention/graphs/contributors
|
| 7 |
|
| 8 |
+
from ...backends import GluonBackend
|
| 9 |
+
from ...modules.causal_conv1d.ops import (
|
| 10 |
CausalConv1dFunction,
|
| 11 |
+
ShortConvolution,
|
| 12 |
+
causal_conv1d,
|
| 13 |
causal_conv1d_bwd,
|
| 14 |
causal_conv1d_fwd,
|
| 15 |
causal_conv1d_update,
|
| 16 |
causal_conv1d_update_states,
|
|
|
|
| 17 |
)
|
| 18 |
|
| 19 |
__all__ = [
|
| 20 |
'CausalConv1dFunction',
|
| 21 |
+
'ShortConvolution',
|
| 22 |
+
'causal_conv1d',
|
| 23 |
'causal_conv1d_bwd',
|
| 24 |
'causal_conv1d_fwd',
|
| 25 |
'causal_conv1d_update',
|
| 26 |
'causal_conv1d_update_states',
|
|
|
|
| 27 |
]
|
| 28 |
+
|
| 29 |
+
|
| 30 |
+
if GluonBackend.is_available():
|
| 31 |
+
from ...modules.causal_conv1d.backends import gluon # noqa: F401
|
build/torch-cuda/modules/causal_conv1d/backends/__init__.py
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright (c) 2023-2026, Songlin Yang, Yu Zhang, Zhiyuan Li
|
| 2 |
+
#
|
| 3 |
+
# This source code is licensed under the MIT license found in the
|
| 4 |
+
# LICENSE file in the root directory of this source tree.
|
| 5 |
+
# For a list of all contributors, visit:
|
| 6 |
+
# https://github.com/fla-org/flash-linear-attention/graphs/contributors
|
build/torch-cuda/modules/{conv → causal_conv1d/backends}/cuda/__init__.py
RENAMED
|
@@ -5,10 +5,6 @@
|
|
| 5 |
# For a list of all contributors, visit:
|
| 6 |
# https://github.com/fla-org/flash-linear-attention/graphs/contributors
|
| 7 |
|
| 8 |
-
from .ops import FastCausalConv1dFn, causal_conv1d_cuda, fast_causal_conv1d_fn
|
| 9 |
|
| 10 |
-
__all__ = [
|
| 11 |
-
'FastCausalConv1dFn',
|
| 12 |
-
'causal_conv1d_cuda',
|
| 13 |
-
'fast_causal_conv1d_fn',
|
| 14 |
-
]
|
|
|
|
| 5 |
# For a list of all contributors, visit:
|
| 6 |
# https://github.com/fla-org/flash-linear-attention/graphs/contributors
|
| 7 |
|
| 8 |
+
from .....modules.causal_conv1d.backends.cuda.ops import FastCausalConv1dFn, causal_conv1d_cuda, fast_causal_conv1d_fn
|
| 9 |
|
| 10 |
+
__all__ = ['FastCausalConv1dFn', 'causal_conv1d_cuda', 'fast_causal_conv1d_fn']
|
|
|
|
|
|
|
|
|
|
|
|
build/torch-cuda/modules/causal_conv1d/backends/cuda/cp.py
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright (c) 2023-2026, Songlin Yang, Yu Zhang, Zhiyuan Li
|
| 2 |
+
#
|
| 3 |
+
# This source code is licensed under the MIT license found in the
|
| 4 |
+
# LICENSE file in the root directory of this source tree.
|
| 5 |
+
# For a list of all contributors, visit:
|
| 6 |
+
# https://github.com/fla-org/flash-linear-attention/graphs/contributors
|
| 7 |
+
|
| 8 |
+
from __future__ import annotations
|
| 9 |
+
|
| 10 |
+
from typing import TYPE_CHECKING
|
| 11 |
+
|
| 12 |
+
import torch
|
| 13 |
+
import torch.nn.functional as F
|
| 14 |
+
|
| 15 |
+
from .....ops.cp import conv_cp_send_recv_bwd, conv_cp_send_recv_fwd
|
| 16 |
+
from .....ops.utils import prepare_sequence_ids
|
| 17 |
+
|
| 18 |
+
if TYPE_CHECKING:
|
| 19 |
+
from torch.distributed import ProcessGroup
|
| 20 |
+
|
| 21 |
+
from .....ops.cp import FLACPContext
|
| 22 |
+
|
| 23 |
+
|
| 24 |
+
class ConvBoundaryExchangeFunction(torch.autograd.Function):
|
| 25 |
+
"""Exchange convolution history and return its gradients to the sending rank."""
|
| 26 |
+
|
| 27 |
+
@staticmethod
|
| 28 |
+
def forward(ctx, tails: torch.Tensor, group: ProcessGroup) -> torch.Tensor:
|
| 29 |
+
ctx.group = group
|
| 30 |
+
return conv_cp_send_recv_fwd(tails=tails, group=group)
|
| 31 |
+
|
| 32 |
+
@staticmethod
|
| 33 |
+
def backward(ctx, dheads: torch.Tensor) -> tuple[torch.Tensor, None]:
|
| 34 |
+
return conv_cp_send_recv_bwd(d_initial_state=dheads.contiguous(), group=ctx.group), None
|
| 35 |
+
|
| 36 |
+
|
| 37 |
+
def causal_conv1d_cuda_cp(
|
| 38 |
+
x: torch.Tensor,
|
| 39 |
+
weight: torch.Tensor,
|
| 40 |
+
bias: torch.Tensor | None,
|
| 41 |
+
residual: torch.Tensor | None,
|
| 42 |
+
activation: str | None,
|
| 43 |
+
cp_context: FLACPContext,
|
| 44 |
+
) -> torch.Tensor:
|
| 45 |
+
"""Apply CUDA convolution to contiguous CP inputs of shape `[1, T, D]`.
|
| 46 |
+
|
| 47 |
+
Each rank needs at least `W - 1` tokens, with `W` in {2, 3, 4}.
|
| 48 |
+
Packed sequence boundaries mask both history values and their gradients.
|
| 49 |
+
"""
|
| 50 |
+
from .....modules.causal_conv1d.backends.cuda.ops import causal_conv1d_fn_cuda
|
| 51 |
+
|
| 52 |
+
if causal_conv1d_fn_cuda is None:
|
| 53 |
+
raise ImportError("CUDA CP requires the causal-conv1d package")
|
| 54 |
+
if cp_context.layout != 'contiguous':
|
| 55 |
+
raise NotImplementedError("CUDA convolution supports only contiguous CP")
|
| 56 |
+
width = weight.shape[-1]
|
| 57 |
+
if width not in (2, 3, 4):
|
| 58 |
+
raise NotImplementedError("CUDA CP convolution supports kernel widths 2, 3, and 4")
|
| 59 |
+
if x.ndim != 3 or x.shape[0] != 1:
|
| 60 |
+
raise ValueError("CUDA CP convolution requires input shape [1, T, D]")
|
| 61 |
+
if x.shape[1] < width - 1:
|
| 62 |
+
raise ValueError("CUDA CP convolution requires at least kernel_width - 1 tokens per rank")
|
| 63 |
+
if cp_context.conv1d_kernel_size != width:
|
| 64 |
+
raise ValueError("CP context kernel width must match the convolution weight")
|
| 65 |
+
if activation not in (None, 'silu', 'swish'):
|
| 66 |
+
raise NotImplementedError("activation must be None, silu, or swish")
|
| 67 |
+
|
| 68 |
+
initial_state = None
|
| 69 |
+
if cp_context.group is not None:
|
| 70 |
+
tails = x[0, -(width - 1):].contiguous()
|
| 71 |
+
heads = ConvBoundaryExchangeFunction.apply(tails, cp_context.group)
|
| 72 |
+
valid_len = min(width - 1, cp_context.pre_num_conv_tokens or 0)
|
| 73 |
+
# history must not cross the first local document's global start
|
| 74 |
+
mask = torch.arange(width - 1, device=x.device) >= width - 1 - valid_len
|
| 75 |
+
initial_state = heads.masked_fill(~mask[:, None], 0).unsqueeze(0)
|
| 76 |
+
|
| 77 |
+
channels = x.shape[-1]
|
| 78 |
+
# the CUDA channel-last kernels require strides divisible by eight
|
| 79 |
+
padding = -channels % 8
|
| 80 |
+
x = F.pad(x, (0, padding)) if padding else x.contiguous()
|
| 81 |
+
if padding:
|
| 82 |
+
weight = F.pad(weight, (0, 0, 0, padding))
|
| 83 |
+
bias = F.pad(bias, (0, padding)) if bias is not None else None
|
| 84 |
+
initial_state = F.pad(initial_state, (0, padding)) if initial_state is not None else None
|
| 85 |
+
|
| 86 |
+
seq_idx = prepare_sequence_ids(cu_seqlens=cp_context.cu_seqlens, cu_seqlens_cpu=cp_context.cu_seqlens_cpu)
|
| 87 |
+
seq_idx = seq_idx.to(torch.int32).unsqueeze(0)
|
| 88 |
+
|
| 89 |
+
y = causal_conv1d_fn_cuda(
|
| 90 |
+
x=x.transpose(1, 2),
|
| 91 |
+
weight=weight,
|
| 92 |
+
bias=bias,
|
| 93 |
+
seq_idx=seq_idx,
|
| 94 |
+
initial_states=initial_state.transpose(1, 2) if initial_state is not None else None,
|
| 95 |
+
activation=activation,
|
| 96 |
+
)
|
| 97 |
+
y = y.transpose(1, 2)[..., :channels]
|
| 98 |
+
return y + residual if residual is not None else y
|
build/{torch-xpu/modules/conv → torch-cuda/modules/causal_conv1d/backends}/cuda/ops.py
RENAMED
|
@@ -5,14 +5,14 @@
|
|
| 5 |
# For a list of all contributors, visit:
|
| 6 |
# https://github.com/fla-org/flash-linear-attention/graphs/contributors
|
| 7 |
|
| 8 |
-
"""CUDA
|
| 9 |
|
| 10 |
import torch
|
| 11 |
from einops import rearrange
|
| 12 |
|
| 13 |
-
from ....modules.
|
| 14 |
-
from ....ops.utils import prepare_sequence_ids
|
| 15 |
-
from ....utils import input_guard
|
| 16 |
|
| 17 |
try:
|
| 18 |
from causal_conv1d.cpp_functions import causal_conv1d_bwd_function
|
|
@@ -26,45 +26,27 @@ except ImportError:
|
|
| 26 |
|
| 27 |
|
| 28 |
class FastCausalConv1dFn(torch.autograd.Function):
|
| 29 |
-
"""
|
| 30 |
-
|
| 31 |
-
|
| 32 |
-
|
| 33 |
-
implementation from TriDao's causal_conv1d CUDA package for backward propagation.
|
| 34 |
-
This hybrid strategy combines the advantages of both technologies:
|
| 35 |
-
|
| 36 |
-
- Forward: Uses FLA's Triton implementation, optimized for the FLA framework
|
| 37 |
-
- Backward: Uses TriDao's causal_conv1d_bwd_function CUDA implementation for faster speed
|
| 38 |
-
|
| 39 |
-
Performance Benefits:
|
| 40 |
-
- CUDA backward implementation is typically faster than the Triton version, reducing training time
|
| 41 |
-
- Maintains the flexibility and compatibility of forward propagation
|
| 42 |
-
|
| 43 |
-
Note:
|
| 44 |
-
- Input/Output format is (batch, seqlen, dim)
|
| 45 |
-
- Backward propagation requires causal_conv1d package: pip install causal-conv1d
|
| 46 |
-
- Supports SILU/Swish activation functions
|
| 47 |
-
- Current limitations (not yet supported):
|
| 48 |
-
* output_final_state must be False
|
| 49 |
-
* initial_states must be None
|
| 50 |
-
* residual must be None
|
| 51 |
"""
|
| 52 |
@staticmethod
|
| 53 |
@input_guard(no_guard_contiguous=["x"])
|
| 54 |
def forward(
|
| 55 |
ctx,
|
| 56 |
-
x,
|
| 57 |
-
weight,
|
| 58 |
-
bias=None,
|
| 59 |
residual: torch.Tensor | None = None,
|
| 60 |
-
initial_states=None,
|
| 61 |
-
output_final_state=False,
|
| 62 |
-
activation=None,
|
| 63 |
cu_seqlens: torch.LongTensor | None = None,
|
| 64 |
cu_seqlens_cpu: torch.LongTensor | None = None,
|
| 65 |
chunk_indices: torch.LongTensor | None = None,
|
| 66 |
seq_idx: torch.LongTensor | None = None,
|
| 67 |
-
):
|
| 68 |
if activation not in [None, "silu", "swish"]:
|
| 69 |
raise NotImplementedError("activation must be None, silu, or swish")
|
| 70 |
assert output_final_state is False, "output_final_state must be False for FastCausalConv1dFn"
|
|
@@ -73,12 +55,11 @@ class FastCausalConv1dFn(torch.autograd.Function):
|
|
| 73 |
|
| 74 |
bias = bias.contiguous() if bias is not None else None
|
| 75 |
if cu_seqlens is not None and seq_idx is None:
|
| 76 |
-
seq_idx = prepare_sequence_ids(cu_seqlens, cu_seqlens_cpu=cu_seqlens_cpu).to(
|
| 77 |
-
torch.int32).unsqueeze(0)
|
| 78 |
seq_idx = seq_idx.contiguous() if seq_idx is not None else None
|
| 79 |
|
| 80 |
-
#
|
| 81 |
-
from ....modules.
|
| 82 |
|
| 83 |
ctx.activation = activation in ["silu", "swish"]
|
| 84 |
out, _ = causal_conv1d_fwd(
|
|
@@ -96,14 +77,12 @@ class FastCausalConv1dFn(torch.autograd.Function):
|
|
| 96 |
|
| 97 |
ctx.save_for_backward(x, weight, bias, seq_idx, initial_states)
|
| 98 |
ctx.return_final_states = output_final_state
|
| 99 |
-
ctx.return_dinitial_states =
|
| 100 |
-
initial_states is not None and initial_states.requires_grad
|
| 101 |
-
)
|
| 102 |
return out, None
|
| 103 |
|
| 104 |
@staticmethod
|
| 105 |
@input_guard
|
| 106 |
-
def backward(ctx, dout, *args):
|
| 107 |
x, weight, bias, seq_idx, initial_states = ctx.saved_tensors
|
| 108 |
dx = torch.empty_like(x, memory_format=torch.contiguous_format)
|
| 109 |
x = rearrange(x, 'b t d -> b d t')
|
|
@@ -113,35 +92,20 @@ class FastCausalConv1dFn(torch.autograd.Function):
|
|
| 113 |
|
| 114 |
if dout.stride(2) != 1 and dout.stride(1) != 1:
|
| 115 |
dout = dout.contiguous()
|
| 116 |
-
# The kernel supports passing in a pre-allocated dx (e.g., in case we want to fuse the
|
| 117 |
-
# backward of conv1d with the backward of chunk).
|
| 118 |
-
# Here we just pass in None and dx will be allocated in the C++ code.
|
| 119 |
dx, dweight, dbias, dinitial_states = causal_conv1d_bwd_function(
|
| 120 |
-
x,
|
| 121 |
-
weight,
|
| 122 |
-
bias,
|
| 123 |
-
dout,
|
| 124 |
-
seq_idx,
|
| 125 |
-
initial_states,
|
| 126 |
-
dfinal_states,
|
| 127 |
-
dx,
|
| 128 |
-
ctx.return_dinitial_states,
|
| 129 |
-
ctx.activation,
|
| 130 |
)
|
| 131 |
dx = rearrange(dx, 'b d t -> b t d')
|
| 132 |
-
return (
|
| 133 |
-
dx,
|
| 134 |
-
dweight,
|
| 135 |
-
dbias if bias is not None else None,
|
| 136 |
-
None,
|
| 137 |
-
None,
|
| 138 |
-
None,
|
| 139 |
-
None,
|
| 140 |
-
None,
|
| 141 |
-
None,
|
| 142 |
-
None,
|
| 143 |
-
None,
|
| 144 |
-
)
|
| 145 |
|
| 146 |
|
| 147 |
def fast_causal_conv1d_fn(
|
|
@@ -156,17 +120,36 @@ def fast_causal_conv1d_fn(
|
|
| 156 |
cu_seqlens_cpu: torch.LongTensor | None = None,
|
| 157 |
chunk_indices: torch.LongTensor | None = None,
|
| 158 |
seq_idx: torch.LongTensor | None = None,
|
| 159 |
-
):
|
| 160 |
-
"""
|
| 161 |
-
|
| 162 |
-
|
| 163 |
-
|
| 164 |
-
|
| 165 |
-
|
| 166 |
-
|
| 167 |
-
|
| 168 |
-
|
| 169 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 170 |
"""
|
| 171 |
assert causal_conv1d_bwd_function is not None, "causal_conv1d_bwd_function is not available"
|
| 172 |
return FastCausalConv1dFn.apply(
|
|
@@ -195,7 +178,7 @@ def causal_conv1d_cuda(
|
|
| 195 |
cu_seqlens: torch.Tensor | None = None,
|
| 196 |
cu_seqlens_cpu: torch.LongTensor | None = None,
|
| 197 |
**kwargs,
|
| 198 |
-
):
|
| 199 |
assert causal_conv1d_fn_cuda is not None, "causal_conv1d_fn_cuda is not available"
|
| 200 |
seq_idx = kwargs.get('seq_idx')
|
| 201 |
if cu_seqlens is not None or seq_idx is not None:
|
|
@@ -205,29 +188,27 @@ def causal_conv1d_cuda(
|
|
| 205 |
x = x.contiguous()
|
| 206 |
x_conv1d = rearrange(x, 'b t d -> b d t')
|
| 207 |
if cu_seqlens is not None and seq_idx is None:
|
| 208 |
-
seq_idx = prepare_sequence_ids(cu_seqlens, cu_seqlens_cpu=cu_seqlens_cpu).to(torch.int32).unsqueeze(0)
|
| 209 |
|
| 210 |
y = causal_conv1d_fn_cuda(
|
| 211 |
x=x_conv1d,
|
| 212 |
weight=weight,
|
| 213 |
bias=bias,
|
| 214 |
-
activation=activation,
|
| 215 |
seq_idx=seq_idx,
|
| 216 |
initial_states=None,
|
| 217 |
return_final_states=False,
|
|
|
|
| 218 |
)
|
| 219 |
|
| 220 |
y = rearrange(y, 'b d t -> b t d')
|
| 221 |
if output_final_state:
|
| 222 |
-
final_state = causal_conv1d_update_states(
|
| 223 |
-
x=x,
|
| 224 |
-
state_len=W,
|
| 225 |
-
initial_state=initial_state,
|
| 226 |
-
cu_seqlens=cu_seqlens,
|
| 227 |
-
)
|
| 228 |
else:
|
| 229 |
final_state = None
|
| 230 |
if residual is not None:
|
| 231 |
y.add_(residual)
|
| 232 |
|
| 233 |
return y, final_state
|
|
|
|
|
|
|
|
|
|
|
|
| 5 |
# For a list of all contributors, visit:
|
| 6 |
# https://github.com/fla-org/flash-linear-attention/graphs/contributors
|
| 7 |
|
| 8 |
+
"""CUDA and mixed Triton/CUDA implementations of causal convolution."""
|
| 9 |
|
| 10 |
import torch
|
| 11 |
from einops import rearrange
|
| 12 |
|
| 13 |
+
from .....modules.causal_conv1d import causal_conv1d_update_states
|
| 14 |
+
from .....ops.utils import prepare_sequence_ids
|
| 15 |
+
from .....utils import input_guard
|
| 16 |
|
| 17 |
try:
|
| 18 |
from causal_conv1d.cpp_functions import causal_conv1d_bwd_function
|
|
|
|
| 26 |
|
| 27 |
|
| 28 |
class FastCausalConv1dFn(torch.autograd.Function):
|
| 29 |
+
"""Causal convolution with Triton forward and CUDA backward on `[B, T, D]` inputs.
|
| 30 |
+
|
| 31 |
+
Backward requires the `causal-conv1d` package. Activation may be `None`, `silu`, or `swish`.
|
| 32 |
+
Residuals and initial/final states are unsupported.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 33 |
"""
|
| 34 |
@staticmethod
|
| 35 |
@input_guard(no_guard_contiguous=["x"])
|
| 36 |
def forward(
|
| 37 |
ctx,
|
| 38 |
+
x: torch.Tensor,
|
| 39 |
+
weight: torch.Tensor,
|
| 40 |
+
bias: torch.Tensor | None = None,
|
| 41 |
residual: torch.Tensor | None = None,
|
| 42 |
+
initial_states: torch.Tensor | None = None,
|
| 43 |
+
output_final_state: bool = False,
|
| 44 |
+
activation: str | None = None,
|
| 45 |
cu_seqlens: torch.LongTensor | None = None,
|
| 46 |
cu_seqlens_cpu: torch.LongTensor | None = None,
|
| 47 |
chunk_indices: torch.LongTensor | None = None,
|
| 48 |
seq_idx: torch.LongTensor | None = None,
|
| 49 |
+
) -> tuple[torch.Tensor, None]:
|
| 50 |
if activation not in [None, "silu", "swish"]:
|
| 51 |
raise NotImplementedError("activation must be None, silu, or swish")
|
| 52 |
assert output_final_state is False, "output_final_state must be False for FastCausalConv1dFn"
|
|
|
|
| 55 |
|
| 56 |
bias = bias.contiguous() if bias is not None else None
|
| 57 |
if cu_seqlens is not None and seq_idx is None:
|
| 58 |
+
seq_idx = prepare_sequence_ids(cu_seqlens=cu_seqlens, cu_seqlens_cpu=cu_seqlens_cpu).to(torch.int32).unsqueeze(0)
|
|
|
|
| 59 |
seq_idx = seq_idx.contiguous() if seq_idx is not None else None
|
| 60 |
|
| 61 |
+
# import here to avoid circular dependency.
|
| 62 |
+
from .....modules.causal_conv1d import causal_conv1d_fwd
|
| 63 |
|
| 64 |
ctx.activation = activation in ["silu", "swish"]
|
| 65 |
out, _ = causal_conv1d_fwd(
|
|
|
|
| 77 |
|
| 78 |
ctx.save_for_backward(x, weight, bias, seq_idx, initial_states)
|
| 79 |
ctx.return_final_states = output_final_state
|
| 80 |
+
ctx.return_dinitial_states = initial_states is not None and initial_states.requires_grad
|
|
|
|
|
|
|
| 81 |
return out, None
|
| 82 |
|
| 83 |
@staticmethod
|
| 84 |
@input_guard
|
| 85 |
+
def backward(ctx, dout: torch.Tensor, *args) -> tuple[torch.Tensor | None, ...]:
|
| 86 |
x, weight, bias, seq_idx, initial_states = ctx.saved_tensors
|
| 87 |
dx = torch.empty_like(x, memory_format=torch.contiguous_format)
|
| 88 |
x = rearrange(x, 'b t d -> b d t')
|
|
|
|
| 92 |
|
| 93 |
if dout.stride(2) != 1 and dout.stride(1) != 1:
|
| 94 |
dout = dout.contiguous()
|
|
|
|
|
|
|
|
|
|
| 95 |
dx, dweight, dbias, dinitial_states = causal_conv1d_bwd_function(
|
| 96 |
+
x=x,
|
| 97 |
+
weight=weight,
|
| 98 |
+
bias=bias,
|
| 99 |
+
dout=dout,
|
| 100 |
+
seq_idx=seq_idx,
|
| 101 |
+
initial_states=initial_states,
|
| 102 |
+
dfinal_states=dfinal_states,
|
| 103 |
+
dx=dx,
|
| 104 |
+
return_dinitial_states=ctx.return_dinitial_states,
|
| 105 |
+
silu_activation=ctx.activation,
|
| 106 |
)
|
| 107 |
dx = rearrange(dx, 'b d t -> b t d')
|
| 108 |
+
return (dx, dweight, dbias if bias is not None else None, None, None, None, None, None, None, None, None)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 109 |
|
| 110 |
|
| 111 |
def fast_causal_conv1d_fn(
|
|
|
|
| 120 |
cu_seqlens_cpu: torch.LongTensor | None = None,
|
| 121 |
chunk_indices: torch.LongTensor | None = None,
|
| 122 |
seq_idx: torch.LongTensor | None = None,
|
| 123 |
+
) -> tuple[torch.Tensor, torch.Tensor | None]:
|
| 124 |
+
"""Apply mixed Triton/CUDA causal convolution to `[B, T, D]` inputs.
|
| 125 |
+
|
| 126 |
+
Args:
|
| 127 |
+
x (torch.Tensor):
|
| 128 |
+
Input of shape `[B, T, D]`.
|
| 129 |
+
weight (torch.Tensor, Optional):
|
| 130 |
+
Convolution weights of shape `[D, W]`. Default: `None`.
|
| 131 |
+
bias (torch.Tensor, Optional):
|
| 132 |
+
Bias of shape `[D]`. Default: `None`.
|
| 133 |
+
residual (torch.Tensor, Optional):
|
| 134 |
+
Unsupported by this backend; must be `None`. Default: `None`.
|
| 135 |
+
initial_state (torch.Tensor, Optional):
|
| 136 |
+
Unsupported by this backend; must be `None`. Default: `None`.
|
| 137 |
+
output_final_state (bool, Optional):
|
| 138 |
+
Unsupported by this backend; must be `False`. Default: `False`.
|
| 139 |
+
activation (str, Optional):
|
| 140 |
+
Activation applied to the output: `None`, `silu`, or `swish`. Default: `None`.
|
| 141 |
+
cu_seqlens (torch.Tensor, Optional):
|
| 142 |
+
Cumulative sequence lengths for packed inputs. Default: `None`.
|
| 143 |
+
cu_seqlens_cpu (torch.LongTensor, Optional):
|
| 144 |
+
CPU copy of `cu_seqlens`. Default: `None`.
|
| 145 |
+
chunk_indices (torch.LongTensor, Optional):
|
| 146 |
+
Precomputed sequence chunk indices. Default: `None`.
|
| 147 |
+
seq_idx (torch.LongTensor, Optional):
|
| 148 |
+
Sequence IDs of shape `[B, T]`. Derived from `cu_seqlens` when omitted. Default: `None`.
|
| 149 |
+
|
| 150 |
+
Returns:
|
| 151 |
+
tuple[torch.Tensor, None]:
|
| 152 |
+
Output of shape `[B, T, D]` and no final state.
|
| 153 |
"""
|
| 154 |
assert causal_conv1d_bwd_function is not None, "causal_conv1d_bwd_function is not available"
|
| 155 |
return FastCausalConv1dFn.apply(
|
|
|
|
| 178 |
cu_seqlens: torch.Tensor | None = None,
|
| 179 |
cu_seqlens_cpu: torch.LongTensor | None = None,
|
| 180 |
**kwargs,
|
| 181 |
+
) -> tuple[torch.Tensor, torch.Tensor | None]:
|
| 182 |
assert causal_conv1d_fn_cuda is not None, "causal_conv1d_fn_cuda is not available"
|
| 183 |
seq_idx = kwargs.get('seq_idx')
|
| 184 |
if cu_seqlens is not None or seq_idx is not None:
|
|
|
|
| 188 |
x = x.contiguous()
|
| 189 |
x_conv1d = rearrange(x, 'b t d -> b d t')
|
| 190 |
if cu_seqlens is not None and seq_idx is None:
|
| 191 |
+
seq_idx = prepare_sequence_ids(cu_seqlens=cu_seqlens, cu_seqlens_cpu=cu_seqlens_cpu).to(torch.int32).unsqueeze(0)
|
| 192 |
|
| 193 |
y = causal_conv1d_fn_cuda(
|
| 194 |
x=x_conv1d,
|
| 195 |
weight=weight,
|
| 196 |
bias=bias,
|
|
|
|
| 197 |
seq_idx=seq_idx,
|
| 198 |
initial_states=None,
|
| 199 |
return_final_states=False,
|
| 200 |
+
activation=activation,
|
| 201 |
)
|
| 202 |
|
| 203 |
y = rearrange(y, 'b d t -> b t d')
|
| 204 |
if output_final_state:
|
| 205 |
+
final_state = causal_conv1d_update_states(x=x, state_len=W, initial_state=initial_state, cu_seqlens=cu_seqlens)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 206 |
else:
|
| 207 |
final_state = None
|
| 208 |
if residual is not None:
|
| 209 |
y.add_(residual)
|
| 210 |
|
| 211 |
return y, final_state
|
| 212 |
+
|
| 213 |
+
|
| 214 |
+
__all__ = ['FastCausalConv1dFn', 'causal_conv1d_cuda', 'fast_causal_conv1d_fn']
|
build/torch-cuda/modules/causal_conv1d/backends/gluon.py
ADDED
|
@@ -0,0 +1,417 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright (c) 2023-2026, Songlin Yang, Yu Zhang, Zhiyuan Li
|
| 2 |
+
#
|
| 3 |
+
# This source code is licensed under the MIT license found in the
|
| 4 |
+
# LICENSE file in the root directory of this source tree.
|
| 5 |
+
# For a list of all contributors, visit:
|
| 6 |
+
# https://github.com/fla-org/flash-linear-attention/graphs/contributors
|
| 7 |
+
|
| 8 |
+
"""Causal depthwise convolution with register reuse and fused backward recomputation."""
|
| 9 |
+
|
| 10 |
+
import torch
|
| 11 |
+
import triton
|
| 12 |
+
from triton.experimental import gluon
|
| 13 |
+
from triton.experimental.gluon import language as gl
|
| 14 |
+
|
| 15 |
+
from ....backends import GluonBackend, register
|
| 16 |
+
from ....modules.causal_conv1d import causal_conv1d_bwd, causal_conv1d_fwd
|
| 17 |
+
from ....ops.utils import prepare_chunk_indices
|
| 18 |
+
from ....utils import input_guard
|
| 19 |
+
|
| 20 |
+
|
| 21 |
+
@gluon.jit(do_not_specialize=['T'])
|
| 22 |
+
def causal_conv1d_fwd_kernel(
|
| 23 |
+
x,
|
| 24 |
+
y,
|
| 25 |
+
weight,
|
| 26 |
+
bias,
|
| 27 |
+
residual,
|
| 28 |
+
cu_seqlens,
|
| 29 |
+
initial_state,
|
| 30 |
+
chunk_indices,
|
| 31 |
+
T,
|
| 32 |
+
SXN: gl.constexpr,
|
| 33 |
+
SXT: gl.constexpr,
|
| 34 |
+
D: gl.constexpr,
|
| 35 |
+
W: gl.constexpr,
|
| 36 |
+
BT: gl.constexpr,
|
| 37 |
+
BD: gl.constexpr,
|
| 38 |
+
BC: gl.constexpr,
|
| 39 |
+
ACTIVATION: gl.constexpr,
|
| 40 |
+
NUM_SPLITS: gl.constexpr = 1,
|
| 41 |
+
):
|
| 42 |
+
layout: gl.constexpr = gl.BlockedLayout(
|
| 43 |
+
size_per_thread=[1, BD // 32],
|
| 44 |
+
threads_per_warp=[1, 32],
|
| 45 |
+
warps_per_cta=[4, 1],
|
| 46 |
+
order=[1, 0],
|
| 47 |
+
)
|
| 48 |
+
i_d = gl.program_id(0).to(gl.int64)
|
| 49 |
+
i_t = gl.program_id(1).to(gl.int64)
|
| 50 |
+
i_b = gl.program_id(2).to(gl.int64)
|
| 51 |
+
i_split = i_t % NUM_SPLITS
|
| 52 |
+
i_t //= NUM_SPLITS
|
| 53 |
+
if cu_seqlens is not None:
|
| 54 |
+
i_n = gl.load(chunk_indices + 2 * i_t).to(gl.int64)
|
| 55 |
+
i_t = gl.load(chunk_indices + 2 * i_t + 1).to(gl.int64)
|
| 56 |
+
bos = gl.load(cu_seqlens + i_n).to(gl.int64)
|
| 57 |
+
T = gl.load(cu_seqlens + i_n + 1).to(gl.int64) - bos
|
| 58 |
+
p_x = x + bos * SXT
|
| 59 |
+
else:
|
| 60 |
+
i_n = i_b
|
| 61 |
+
bos = i_b * T
|
| 62 |
+
p_x = x + i_b * SXN
|
| 63 |
+
o_d = i_d * BD + gl.arange(0, BD, layout=gl.SliceLayout(0, layout)).to(gl.int64)
|
| 64 |
+
o_t = (i_t * NUM_SPLITS + i_split) * BT
|
| 65 |
+
o_t += gl.arange(0, BT // BC, layout=gl.SliceLayout(1, layout)).to(gl.int64) * BC
|
| 66 |
+
b_x = ()
|
| 67 |
+
b_w = ()
|
| 68 |
+
for i_w in gl.static_range(W):
|
| 69 |
+
b_w += (gl.load(weight + o_d * W + i_w, mask=o_d < D, other=0).to(gl.float32),)
|
| 70 |
+
# each row unrolls BC outputs from one register window; adjacent outputs reuse inputs.
|
| 71 |
+
# with W=4:
|
| 72 |
+
# y[t] <- x[t-3] x[t-2] x[t-1] x[t]
|
| 73 |
+
# y[t+1] <- x[t-2] x[t-1] x[t] x[t+1]
|
| 74 |
+
for i_x in gl.static_range(BC + W - 1):
|
| 75 |
+
o_x = o_t + i_x - W + 1
|
| 76 |
+
b_xi = gl.load(
|
| 77 |
+
pointer=p_x + o_x[:, None] * SXT + o_d[None, :],
|
| 78 |
+
mask=(o_x[:, None] >= 0) & (o_x[:, None] < T) & (o_d[None, :] < D),
|
| 79 |
+
other=0,
|
| 80 |
+
).to(gl.float32)
|
| 81 |
+
if initial_state is not None:
|
| 82 |
+
b_xi += gl.load(
|
| 83 |
+
pointer=initial_state + i_n * D * W + o_d[None, :] * W + (o_x[:, None] + W),
|
| 84 |
+
mask=(o_x[:, None] < 0) & (o_x[:, None] >= 1 - W) & (o_d[None, :] < D),
|
| 85 |
+
other=0,
|
| 86 |
+
).to(gl.float32)
|
| 87 |
+
b_x += (b_xi,)
|
| 88 |
+
if bias is not None:
|
| 89 |
+
b_bias = gl.load(bias + o_d, mask=o_d < D, other=0).to(gl.float32)
|
| 90 |
+
for i_r in gl.static_range(BC):
|
| 91 |
+
b_y = gl.full((BT // BC, BD), 0, gl.float32, layout)
|
| 92 |
+
for i_w in gl.static_range(W):
|
| 93 |
+
b_y += b_x[i_r + i_w] * b_w[i_w][None, :]
|
| 94 |
+
if bias is not None:
|
| 95 |
+
b_y += b_bias[None, :]
|
| 96 |
+
if ACTIVATION == 'silu' or ACTIVATION == 'swish':
|
| 97 |
+
b_y *= 1. / (1. + gl.exp(-b_y))
|
| 98 |
+
o_y = (bos + o_t[:, None] + i_r) * D + o_d[None, :]
|
| 99 |
+
m_y = (o_t[:, None] + i_r < T) & (o_d[None, :] < D)
|
| 100 |
+
if residual is not None:
|
| 101 |
+
b_y += gl.load(residual + o_y, mask=m_y, other=0).to(gl.float32)
|
| 102 |
+
gl.store(y + o_y, b_y, mask=m_y)
|
| 103 |
+
|
| 104 |
+
|
| 105 |
+
@gluon.jit(do_not_specialize=['T'])
|
| 106 |
+
def causal_conv1d_bwd_kernel(
|
| 107 |
+
x,
|
| 108 |
+
weight,
|
| 109 |
+
bias,
|
| 110 |
+
dy,
|
| 111 |
+
dx,
|
| 112 |
+
dw_partial,
|
| 113 |
+
db_partial,
|
| 114 |
+
cu_seqlens,
|
| 115 |
+
chunk_indices,
|
| 116 |
+
T,
|
| 117 |
+
SXN: gl.constexpr,
|
| 118 |
+
SXT: gl.constexpr,
|
| 119 |
+
SYN: gl.constexpr,
|
| 120 |
+
SYT: gl.constexpr,
|
| 121 |
+
SYD: gl.constexpr,
|
| 122 |
+
D: gl.constexpr,
|
| 123 |
+
W: gl.constexpr,
|
| 124 |
+
BT: gl.constexpr,
|
| 125 |
+
BD: gl.constexpr,
|
| 126 |
+
BC: gl.constexpr,
|
| 127 |
+
ACTIVATION: gl.constexpr,
|
| 128 |
+
):
|
| 129 |
+
layout: gl.constexpr = gl.BlockedLayout(
|
| 130 |
+
size_per_thread=[1, BD // 32],
|
| 131 |
+
threads_per_warp=[1, 32],
|
| 132 |
+
warps_per_cta=[4, 1],
|
| 133 |
+
order=[1, 0],
|
| 134 |
+
)
|
| 135 |
+
i_d = gl.program_id(0).to(gl.int64)
|
| 136 |
+
i_t = gl.program_id(1).to(gl.int64)
|
| 137 |
+
i_b = gl.program_id(2).to(gl.int64)
|
| 138 |
+
i_tg = i_b * gl.num_programs(1) + i_t
|
| 139 |
+
if cu_seqlens is not None:
|
| 140 |
+
i_n = gl.load(chunk_indices + 2 * i_t).to(gl.int64)
|
| 141 |
+
i_t = gl.load(chunk_indices + 2 * i_t + 1).to(gl.int64)
|
| 142 |
+
bos = gl.load(cu_seqlens + i_n).to(gl.int64)
|
| 143 |
+
T = gl.load(cu_seqlens + i_n + 1).to(gl.int64) - bos
|
| 144 |
+
p_x = x + bos * SXT
|
| 145 |
+
p_dy = dy + bos * SYT
|
| 146 |
+
else:
|
| 147 |
+
bos = i_b * T
|
| 148 |
+
p_x = x + i_b * SXN
|
| 149 |
+
p_dy = dy + i_b * SYN
|
| 150 |
+
o_d = i_d * BD + gl.arange(0, BD, layout=gl.SliceLayout(0, layout)).to(gl.int64)
|
| 151 |
+
# each row unrolls BC consecutive tokens within the BT-token tile.
|
| 152 |
+
# rows (BT=64, BC=16): [0..15] [16..31] [32..47] [48..63]
|
| 153 |
+
o_t = i_t * BT + gl.arange(0, BT // BC, layout=gl.SliceLayout(1, layout)).to(gl.int64) * BC
|
| 154 |
+
b_w = ()
|
| 155 |
+
b_x = ()
|
| 156 |
+
b_dy = ()
|
| 157 |
+
b_dw = ()
|
| 158 |
+
for i_w in gl.static_range(W):
|
| 159 |
+
b_w += (gl.load(weight + o_d * W + i_w, mask=o_d < D, other=0).to(gl.float32),)
|
| 160 |
+
b_dw += (gl.full((BT // BC, BD), 0, gl.float32, layout),)
|
| 161 |
+
if bias is not None:
|
| 162 |
+
b_bias = gl.load(bias + o_d, mask=o_d < D, other=0).to(gl.float32)
|
| 163 |
+
for i_x in gl.static_range(BC + 2 * W - 2):
|
| 164 |
+
o_x = o_t + i_x - W + 1
|
| 165 |
+
b_xi = gl.load(
|
| 166 |
+
pointer=p_x + o_x[:, None] * SXT + o_d[None, :],
|
| 167 |
+
mask=(o_x[:, None] >= 0) & (o_x[:, None] < T) & (o_d[None, :] < D),
|
| 168 |
+
other=0,
|
| 169 |
+
).to(gl.float32)
|
| 170 |
+
b_x += (b_xi,)
|
| 171 |
+
for i_r in gl.static_range(BC + W - 1):
|
| 172 |
+
b_dyi = gl.load(
|
| 173 |
+
pointer=p_dy + (o_t[:, None] + i_r) * SYT + o_d[None, :] * SYD,
|
| 174 |
+
mask=(o_t[:, None] + i_r < T) & (o_d[None, :] < D),
|
| 175 |
+
other=0,
|
| 176 |
+
).to(gl.float32)
|
| 177 |
+
if ACTIVATION == 'silu' or ACTIVATION == 'swish':
|
| 178 |
+
b_y = gl.full((BT // BC, BD), 0, gl.float32, layout)
|
| 179 |
+
for i_w in gl.static_range(W):
|
| 180 |
+
b_y += b_x[i_r + i_w] * b_w[i_w][None, :]
|
| 181 |
+
if bias is not None:
|
| 182 |
+
b_y += b_bias[None, :]
|
| 183 |
+
# backward preserves the baseline's rounded recomputed preactivation.
|
| 184 |
+
b_y = b_y.to(x.dtype.element_ty).to(gl.float32)
|
| 185 |
+
b_ys = 1. / (1. + gl.exp(-b_y))
|
| 186 |
+
b_dyi = b_dyi * b_ys * (1 + b_y * (1 - b_ys))
|
| 187 |
+
b_dy += (b_dyi,)
|
| 188 |
+
b_db = gl.full((BT // BC, BD), 0, gl.float32, layout)
|
| 189 |
+
for i_r in gl.static_range(BC):
|
| 190 |
+
b_dx = gl.full((BT // BC, BD), 0, gl.float32, layout)
|
| 191 |
+
b_dw_new = ()
|
| 192 |
+
for i_w in gl.static_range(W):
|
| 193 |
+
b_dyi = b_dy[i_r + i_w]
|
| 194 |
+
b_dx += b_dyi * b_w[W - i_w - 1][None, :]
|
| 195 |
+
b_dw_new += (b_dw[i_w] + b_dyi * b_x[i_r + W - 1],)
|
| 196 |
+
b_dw = b_dw_new
|
| 197 |
+
b_db += b_dy[i_r]
|
| 198 |
+
gl.store(
|
| 199 |
+
pointer=dx + (bos + o_t[:, None] + i_r) * D + o_d[None, :],
|
| 200 |
+
value=b_dx,
|
| 201 |
+
mask=(o_t[:, None] + i_r < T) & (o_d[None, :] < D),
|
| 202 |
+
)
|
| 203 |
+
for i_w in gl.static_range(W):
|
| 204 |
+
gl.store(pointer=dw_partial + i_tg * D * W + o_d * W + W - i_w - 1, value=gl.sum(b_dw[i_w], axis=0), mask=o_d < D)
|
| 205 |
+
if db_partial is not None:
|
| 206 |
+
gl.store(db_partial + i_tg * D + o_d, gl.sum(b_db, axis=0), mask=o_d < D)
|
| 207 |
+
|
| 208 |
+
|
| 209 |
+
@gluon.jit(do_not_specialize=['NP'])
|
| 210 |
+
def causal_conv1d_bwd_kernel_dwdb(dw_partial, db_partial, dw, db, NP, D: gl.constexpr, W: gl.constexpr, BD: gl.constexpr):
|
| 211 |
+
BN: gl.constexpr = 128
|
| 212 |
+
layout: gl.constexpr = gl.BlockedLayout(
|
| 213 |
+
size_per_thread=[1, BD // 32],
|
| 214 |
+
threads_per_warp=[1, 32],
|
| 215 |
+
warps_per_cta=[4, 1],
|
| 216 |
+
order=[1, 0],
|
| 217 |
+
)
|
| 218 |
+
i_d = gl.program_id(0).to(gl.int64)
|
| 219 |
+
o_d = i_d * BD + gl.arange(0, BD, layout=gl.SliceLayout(0, layout)).to(gl.int64)
|
| 220 |
+
b_dw = gl.full((BD,), 0, gl.float32, gl.SliceLayout(0, layout))
|
| 221 |
+
for i_n in range(0, NP, BN):
|
| 222 |
+
o_n = i_n + gl.arange(0, BN, layout=gl.SliceLayout(1, layout)).to(gl.int64)
|
| 223 |
+
b_partial = gl.load(
|
| 224 |
+
pointer=dw_partial + o_n[:, None] * D * W + o_d[None, :],
|
| 225 |
+
mask=(o_n[:, None] < NP) & (o_d[None, :] < D * W),
|
| 226 |
+
other=0,
|
| 227 |
+
)
|
| 228 |
+
b_dw += gl.sum(b_partial, axis=0)
|
| 229 |
+
gl.store(dw + o_d, b_dw.to(dw.dtype.element_ty), mask=o_d < D * W)
|
| 230 |
+
if db_partial is not None:
|
| 231 |
+
if i_d * BD < D:
|
| 232 |
+
b_db = gl.full((BD,), 0, gl.float32, gl.SliceLayout(0, layout))
|
| 233 |
+
for i_n in range(0, NP, BN):
|
| 234 |
+
o_n = i_n + gl.arange(0, BN, layout=gl.SliceLayout(1, layout)).to(gl.int64)
|
| 235 |
+
b_partial = gl.load(
|
| 236 |
+
pointer=db_partial + o_n[:, None] * D + o_d[None, :],
|
| 237 |
+
mask=(o_n[:, None] < NP) & (o_d[None, :] < D),
|
| 238 |
+
other=0,
|
| 239 |
+
)
|
| 240 |
+
b_db += gl.sum(b_partial, axis=0)
|
| 241 |
+
gl.store(db + o_d, b_db.to(db.dtype.element_ty), mask=o_d < D)
|
| 242 |
+
|
| 243 |
+
|
| 244 |
+
def causal_conv1d_fwd_verifier(
|
| 245 |
+
x: torch.Tensor,
|
| 246 |
+
weight: torch.Tensor | None,
|
| 247 |
+
bias: torch.Tensor | None = None,
|
| 248 |
+
residual: torch.Tensor | None = None,
|
| 249 |
+
initial_state: torch.Tensor | None = None,
|
| 250 |
+
output_final_state: bool = False,
|
| 251 |
+
activation: str | None = None,
|
| 252 |
+
cu_seqlens: torch.LongTensor | None = None,
|
| 253 |
+
cu_seqlens_cpu: torch.LongTensor | None = None,
|
| 254 |
+
chunk_indices: torch.LongTensor | None = None,
|
| 255 |
+
chunk_size: int = 64,
|
| 256 |
+
layout_fallback: bool = False,
|
| 257 |
+
) -> tuple[bool, str | None]:
|
| 258 |
+
if torch.distributed.is_initialized():
|
| 259 |
+
return False, "Gluon convolution does not support distributed execution"
|
| 260 |
+
if x.dtype not in (torch.float16, torch.bfloat16, torch.float32):
|
| 261 |
+
return False, "Gluon convolution supports float16, bfloat16, and float32"
|
| 262 |
+
if x.ndim != 3 or x.stride(-1) != 1:
|
| 263 |
+
return False, "Gluon convolution requires [B, T, D] with contiguous channels"
|
| 264 |
+
if weight is None or weight.shape[0] != x.shape[-1] or weight.shape[1] not in (2, 3, 4):
|
| 265 |
+
return False, "Gluon convolution requires a width of 2, 3, or 4"
|
| 266 |
+
if cu_seqlens is not None and x.shape[0] != 1:
|
| 267 |
+
return False, "Gluon packed convolution requires batch size 1"
|
| 268 |
+
if chunk_size != 64:
|
| 269 |
+
return False, "Gluon convolution requires 64-token chunk indices"
|
| 270 |
+
return True, None
|
| 271 |
+
|
| 272 |
+
|
| 273 |
+
@register(causal_conv1d_fwd, backend=GluonBackend, verifier=causal_conv1d_fwd_verifier, env_var='FLA_CONV_GLUON')
|
| 274 |
+
@input_guard(no_guard_contiguous=['x'])
|
| 275 |
+
def causal_conv1d_fwd_gluon(
|
| 276 |
+
x: torch.Tensor,
|
| 277 |
+
weight: torch.Tensor,
|
| 278 |
+
bias: torch.Tensor | None = None,
|
| 279 |
+
residual: torch.Tensor | None = None,
|
| 280 |
+
initial_state: torch.Tensor | None = None,
|
| 281 |
+
output_final_state: bool = False,
|
| 282 |
+
activation: str | None = None,
|
| 283 |
+
cu_seqlens: torch.LongTensor | None = None,
|
| 284 |
+
cu_seqlens_cpu: torch.LongTensor | None = None,
|
| 285 |
+
chunk_indices: torch.LongTensor | None = None,
|
| 286 |
+
chunk_size: int = 64,
|
| 287 |
+
layout_fallback: bool = False,
|
| 288 |
+
) -> tuple[torch.Tensor, torch.Tensor | None]:
|
| 289 |
+
del layout_fallback
|
| 290 |
+
BT = chunk_size
|
| 291 |
+
B, T, D = x.shape
|
| 292 |
+
if cu_seqlens is not None and chunk_indices is None:
|
| 293 |
+
chunk_indices = prepare_chunk_indices(cu_seqlens=cu_seqlens, chunk_size=BT, cu_seqlens_cpu=cu_seqlens_cpu)
|
| 294 |
+
NT = len(chunk_indices) if cu_seqlens is not None else triton.cdiv(T, BT)
|
| 295 |
+
y = torch.empty_like(x, memory_format=torch.contiguous_format)
|
| 296 |
+
use_small_tile = B * T * D <= 1048576
|
| 297 |
+
BD, num_splits = (32, 2) if use_small_tile else (64, 1)
|
| 298 |
+
causal_conv1d_fwd_kernel[(triton.cdiv(D, BD), NT * num_splits, B)](
|
| 299 |
+
x=x,
|
| 300 |
+
y=y,
|
| 301 |
+
weight=weight,
|
| 302 |
+
bias=bias,
|
| 303 |
+
residual=residual,
|
| 304 |
+
cu_seqlens=cu_seqlens,
|
| 305 |
+
initial_state=initial_state,
|
| 306 |
+
chunk_indices=chunk_indices,
|
| 307 |
+
T=T,
|
| 308 |
+
SXN=x.stride(0),
|
| 309 |
+
SXT=x.stride(1),
|
| 310 |
+
D=D,
|
| 311 |
+
W=weight.shape[1],
|
| 312 |
+
BT=BT // num_splits,
|
| 313 |
+
BD=BD,
|
| 314 |
+
BC=8,
|
| 315 |
+
ACTIVATION=activation,
|
| 316 |
+
NUM_SPLITS=num_splits,
|
| 317 |
+
num_warps=4,
|
| 318 |
+
)
|
| 319 |
+
final_state = None
|
| 320 |
+
if output_final_state:
|
| 321 |
+
from ....modules.causal_conv1d import causal_conv1d_update_states
|
| 322 |
+
|
| 323 |
+
final_state = causal_conv1d_update_states(
|
| 324 |
+
x=x,
|
| 325 |
+
state_len=weight.shape[1],
|
| 326 |
+
initial_state=initial_state,
|
| 327 |
+
cu_seqlens=cu_seqlens,
|
| 328 |
+
)
|
| 329 |
+
return y, final_state
|
| 330 |
+
|
| 331 |
+
|
| 332 |
+
def causal_conv1d_bwd_verifier(
|
| 333 |
+
x: torch.Tensor,
|
| 334 |
+
dy: torch.Tensor,
|
| 335 |
+
dht: torch.Tensor | None,
|
| 336 |
+
weight: torch.Tensor | None = None,
|
| 337 |
+
bias: torch.Tensor | None = None,
|
| 338 |
+
residual: torch.Tensor | None = None,
|
| 339 |
+
initial_state: torch.Tensor | None = None,
|
| 340 |
+
activation: str | None = None,
|
| 341 |
+
cu_seqlens: torch.LongTensor | None = None,
|
| 342 |
+
cu_seqlens_cpu: torch.LongTensor | None = None,
|
| 343 |
+
chunk_indices: torch.LongTensor | None = None,
|
| 344 |
+
chunk_size: int = 64,
|
| 345 |
+
layout_fallback: bool = False,
|
| 346 |
+
) -> tuple[bool, str | None]:
|
| 347 |
+
if initial_state is not None or dht is not None:
|
| 348 |
+
return False, "Gluon convolution does not support state gradients"
|
| 349 |
+
return causal_conv1d_fwd_verifier(x=x, weight=weight, cu_seqlens=cu_seqlens, chunk_size=chunk_size)
|
| 350 |
+
|
| 351 |
+
|
| 352 |
+
@register(causal_conv1d_bwd, backend=GluonBackend, verifier=causal_conv1d_bwd_verifier, env_var='FLA_CONV_GLUON')
|
| 353 |
+
def causal_conv1d_bwd_gluon(
|
| 354 |
+
x: torch.Tensor,
|
| 355 |
+
dy: torch.Tensor,
|
| 356 |
+
dht: torch.Tensor | None,
|
| 357 |
+
weight: torch.Tensor | None = None,
|
| 358 |
+
bias: torch.Tensor | None = None,
|
| 359 |
+
residual: torch.Tensor | None = None,
|
| 360 |
+
initial_state: torch.Tensor | None = None,
|
| 361 |
+
activation: str | None = None,
|
| 362 |
+
cu_seqlens: torch.LongTensor | None = None,
|
| 363 |
+
cu_seqlens_cpu: torch.LongTensor | None = None,
|
| 364 |
+
chunk_indices: torch.LongTensor | None = None,
|
| 365 |
+
chunk_size: int = 64,
|
| 366 |
+
layout_fallback: bool = False,
|
| 367 |
+
) -> tuple[torch.Tensor, torch.Tensor, torch.Tensor | None, torch.Tensor | None, None]:
|
| 368 |
+
del layout_fallback
|
| 369 |
+
BT = chunk_size
|
| 370 |
+
B, T, D = x.shape
|
| 371 |
+
W = weight.shape[1]
|
| 372 |
+
BD = 32
|
| 373 |
+
if cu_seqlens is not None and chunk_indices is None:
|
| 374 |
+
chunk_indices = prepare_chunk_indices(cu_seqlens=cu_seqlens, chunk_size=BT, cu_seqlens_cpu=cu_seqlens_cpu)
|
| 375 |
+
NT = len(chunk_indices) if cu_seqlens is not None else triton.cdiv(T, BT)
|
| 376 |
+
dx = torch.empty_like(x, memory_format=torch.contiguous_format)
|
| 377 |
+
dw_partial = weight.new_empty((B * NT, D, W), dtype=torch.float32)
|
| 378 |
+
db_partial = bias.new_empty((B * NT, D), dtype=torch.float32) if bias is not None else None
|
| 379 |
+
causal_conv1d_bwd_kernel[(triton.cdiv(D, BD), NT, B)](
|
| 380 |
+
x=x,
|
| 381 |
+
weight=weight,
|
| 382 |
+
bias=bias,
|
| 383 |
+
dy=dy,
|
| 384 |
+
dx=dx,
|
| 385 |
+
dw_partial=dw_partial,
|
| 386 |
+
db_partial=db_partial,
|
| 387 |
+
cu_seqlens=cu_seqlens,
|
| 388 |
+
chunk_indices=chunk_indices,
|
| 389 |
+
T=T,
|
| 390 |
+
SXN=x.stride(0),
|
| 391 |
+
SXT=x.stride(1),
|
| 392 |
+
SYN=dy.stride(0),
|
| 393 |
+
SYT=dy.stride(1),
|
| 394 |
+
SYD=dy.stride(2),
|
| 395 |
+
D=D,
|
| 396 |
+
W=W,
|
| 397 |
+
BT=BT,
|
| 398 |
+
BD=BD,
|
| 399 |
+
BC=16,
|
| 400 |
+
ACTIVATION=activation,
|
| 401 |
+
num_warps=4,
|
| 402 |
+
)
|
| 403 |
+
dw = weight.new_empty((D, W))
|
| 404 |
+
db = bias.new_empty((D,)) if bias is not None else None
|
| 405 |
+
causal_conv1d_bwd_kernel_dwdb[(triton.cdiv(D * W, BD),)](
|
| 406 |
+
dw_partial=dw_partial,
|
| 407 |
+
db_partial=db_partial,
|
| 408 |
+
dw=dw,
|
| 409 |
+
db=db,
|
| 410 |
+
NP=B * NT,
|
| 411 |
+
D=D,
|
| 412 |
+
W=W,
|
| 413 |
+
BD=BD,
|
| 414 |
+
num_warps=4,
|
| 415 |
+
)
|
| 416 |
+
dr = dy if residual is not None else None
|
| 417 |
+
return dx, dw, db, dr, None
|
build/torch-cuda/modules/{conv/cp/ops.py → causal_conv1d/cp.py}
RENAMED
|
@@ -8,8 +8,8 @@
|
|
| 8 |
import torch
|
| 9 |
import torch.distributed as dist
|
| 10 |
|
| 11 |
-
from ...
|
| 12 |
-
from ...
|
| 13 |
|
| 14 |
|
| 15 |
class CausalConv1dFunctionCP(torch.autograd.Function):
|
|
@@ -36,28 +36,58 @@ class CausalConv1dFunctionCP(torch.autograd.Function):
|
|
| 36 |
"""Prepare initial_state for CP forward pass by communicating with previous rank.
|
| 37 |
|
| 38 |
Args:
|
| 39 |
-
x
|
| 40 |
-
|
| 41 |
-
|
| 42 |
-
|
| 43 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 44 |
|
| 45 |
Returns:
|
| 46 |
-
initial_state
|
|
|
|
| 47 |
"""
|
| 48 |
-
|
|
|
|
| 49 |
return None
|
| 50 |
|
| 51 |
-
W = weight.shape[-1] # weight: [D, W]
|
| 52 |
D = weight.shape[0]
|
| 53 |
initial_state = None
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 54 |
if not context.is_first_rank:
|
| 55 |
-
#
|
| 56 |
assert x.dim() == 3 and x.shape[0] == 1, f"CP requires [1, T, D], got {x.shape}"
|
| 57 |
x_2d = x.squeeze(0) # [T, D]
|
| 58 |
tails = x_2d[-(W-1):].contiguous() # [W-1, D]
|
| 59 |
heads = conv_cp_send_recv_fwd(tails, group) # [W-1, D]
|
| 60 |
-
#
|
| 61 |
N = len(cu_seqlens) - 1
|
| 62 |
initial_state = torch.zeros(N, D, W, device=x.device, dtype=x.dtype)
|
| 63 |
valid_len = min(W - 1, context.pre_num_conv_tokens)
|
|
@@ -65,10 +95,11 @@ class CausalConv1dFunctionCP(torch.autograd.Function):
|
|
| 65 |
# heads[-valid_len:]: [valid_len, D] -> [D, valid_len]
|
| 66 |
initial_state[0, :, -valid_len:] = heads[-valid_len:].T
|
| 67 |
else:
|
| 68 |
-
#
|
| 69 |
x_2d = x.squeeze(0)
|
| 70 |
tails = x_2d[-(W-1):].contiguous()
|
| 71 |
-
|
|
|
|
| 72 |
|
| 73 |
return initial_state
|
| 74 |
|
|
@@ -78,25 +109,46 @@ class CausalConv1dFunctionCP(torch.autograd.Function):
|
|
| 78 |
dh0: torch.Tensor | None,
|
| 79 |
W: int,
|
| 80 |
group: dist.ProcessGroup | None,
|
| 81 |
-
|
| 82 |
-
pre_num_conv_tokens: int = 0,
|
| 83 |
) -> None:
|
| 84 |
"""Correct dx gradients for CP backward pass by communicating with next rank.
|
| 85 |
|
| 86 |
Args:
|
| 87 |
-
dx
|
| 88 |
-
|
| 89 |
-
|
| 90 |
-
|
| 91 |
-
|
| 92 |
-
|
| 93 |
-
|
| 94 |
-
|
|
|
|
|
|
|
| 95 |
"""
|
| 96 |
-
if group is None:
|
| 97 |
return
|
| 98 |
|
| 99 |
D = dx.shape[-1]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 100 |
# dh0: [N, D, W] or None
|
| 101 |
# We only care about the first sequence's initial_state gradient
|
| 102 |
if dh0 is not None:
|
|
@@ -104,13 +156,13 @@ class CausalConv1dFunctionCP(torch.autograd.Function):
|
|
| 104 |
# previous rank. The forward fills only the last valid_len positions
|
| 105 |
# of initial_state; gradients for the remaining (zero-padded) positions
|
| 106 |
# must not flow back, otherwise they leak into unrelated sequences.
|
| 107 |
-
valid_len = min(W - 1, pre_num_conv_tokens)
|
| 108 |
d_initial_state = torch.zeros(W-1, D, device=dx.device, dtype=dx.dtype)
|
| 109 |
if valid_len > 0:
|
| 110 |
d_initial_state[-valid_len:] = dh0[0, :, -valid_len:].T
|
| 111 |
else:
|
| 112 |
# dh0 is None only when this is the first rank (no initial_state needed)
|
| 113 |
-
assert is_first_rank, "dh0 should not be None when is_first_rank=False"
|
| 114 |
d_initial_state = torch.zeros(W-1, D, device=dx.device, dtype=dx.dtype)
|
| 115 |
# Sync communication: send d_initial_state to previous rank, receive from next rank
|
| 116 |
recv_d_init = conv_cp_send_recv_bwd(d_initial_state, group) # [W-1, D]
|
|
@@ -128,9 +180,10 @@ class CausalConv1dFunctionCP(torch.autograd.Function):
|
|
| 128 |
cp_context: FLACPContext | None,
|
| 129 |
chunk_size: int | None,
|
| 130 |
backend: str = 'triton',
|
| 131 |
-
|
| 132 |
-
|
| 133 |
-
|
|
|
|
| 134 |
|
| 135 |
if cp_context is None:
|
| 136 |
raise ValueError("cp_context must be provided for CausalConv1dFunctionCP")
|
|
@@ -138,9 +191,9 @@ class CausalConv1dFunctionCP(torch.autograd.Function):
|
|
| 138 |
cu_seqlens_cpu = cp_context.cu_seqlens_cpu
|
| 139 |
group = cp_context.group
|
| 140 |
|
| 141 |
-
#
|
| 142 |
W = weight.shape[-1] # weight: [D, W]
|
| 143 |
-
#
|
| 144 |
initial_state = CausalConv1dFunctionCP._prepare_initial_state_for_cp(
|
| 145 |
x=x,
|
| 146 |
weight=weight,
|
|
@@ -149,7 +202,7 @@ class CausalConv1dFunctionCP(torch.autograd.Function):
|
|
| 149 |
group=group,
|
| 150 |
)
|
| 151 |
|
| 152 |
-
ctx.save_for_backward(x, weight, bias, initial_state)
|
| 153 |
ctx.activation = activation
|
| 154 |
ctx.cu_seqlens = cu_seqlens
|
| 155 |
ctx.cu_seqlens_cpu = cu_seqlens_cpu
|
|
@@ -157,62 +210,54 @@ class CausalConv1dFunctionCP(torch.autograd.Function):
|
|
| 157 |
ctx.chunk_size = chunk_size
|
| 158 |
ctx.group = group
|
| 159 |
ctx.W = W
|
| 160 |
-
ctx.
|
| 161 |
-
ctx.pre_num_conv_tokens = cp_context.pre_num_conv_tokens
|
| 162 |
|
| 163 |
-
#
|
| 164 |
y, _ = causal_conv1d_fwd(
|
| 165 |
x=x,
|
| 166 |
weight=weight,
|
| 167 |
bias=bias,
|
| 168 |
-
residual=
|
| 169 |
initial_state=initial_state,
|
| 170 |
output_final_state=False,
|
| 171 |
activation=activation,
|
| 172 |
cu_seqlens=cu_seqlens,
|
| 173 |
cu_seqlens_cpu=cu_seqlens_cpu,
|
| 174 |
chunk_indices=chunk_indices,
|
| 175 |
-
|
| 176 |
)
|
| 177 |
|
| 178 |
return y
|
| 179 |
|
| 180 |
@staticmethod
|
| 181 |
-
def backward(ctx, dy: torch.Tensor):
|
| 182 |
-
#
|
| 183 |
-
from ...
|
| 184 |
|
| 185 |
-
x, weight, bias, initial_state = ctx.saved_tensors
|
| 186 |
group = ctx.group
|
| 187 |
W = ctx.W
|
| 188 |
|
| 189 |
-
#
|
| 190 |
-
dx, dw, db,
|
| 191 |
x=x,
|
| 192 |
dy=dy,
|
| 193 |
dht=None,
|
| 194 |
weight=weight,
|
| 195 |
bias=bias,
|
| 196 |
-
residual=
|
| 197 |
initial_state=initial_state,
|
| 198 |
activation=ctx.activation,
|
| 199 |
cu_seqlens=ctx.cu_seqlens,
|
| 200 |
cu_seqlens_cpu=ctx.cu_seqlens_cpu,
|
| 201 |
chunk_indices=ctx.chunk_indices,
|
| 202 |
-
|
| 203 |
)
|
| 204 |
|
| 205 |
-
#
|
| 206 |
-
CausalConv1dFunctionCP._correct_dx_for_cp(
|
| 207 |
-
dx=dx,
|
| 208 |
-
dh0=dh0,
|
| 209 |
-
W=W,
|
| 210 |
-
group=group,
|
| 211 |
-
is_first_rank=ctx.is_first_rank,
|
| 212 |
-
pre_num_conv_tokens=ctx.pre_num_conv_tokens,
|
| 213 |
-
)
|
| 214 |
|
| 215 |
-
return dx, dw, db, None, None, None, None, None
|
| 216 |
|
| 217 |
|
| 218 |
def causal_conv1d_cp(
|
|
@@ -224,35 +269,62 @@ def causal_conv1d_cp(
|
|
| 224 |
cp_context: FLACPContext | None = None,
|
| 225 |
chunk_size: int | None = None,
|
| 226 |
backend: str = 'triton',
|
| 227 |
-
|
| 228 |
-
|
| 229 |
-
|
| 230 |
-
|
| 231 |
-
Automatically handles communication in CP environment:
|
| 232 |
-
- Forward: get initial_state from previous rank
|
| 233 |
-
- Backward: correct dx gradients
|
| 234 |
|
| 235 |
Args:
|
| 236 |
-
x
|
| 237 |
-
|
| 238 |
-
|
| 239 |
-
|
| 240 |
-
|
| 241 |
-
|
| 242 |
-
|
| 243 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 244 |
"""
|
| 245 |
if cp_context is None:
|
| 246 |
raise ValueError("cp_context must be provided for causal_conv1d_cp")
|
| 247 |
|
| 248 |
assert cp_context.conv1d_kernel_size is not None, "conv1d_kernel_size must be provided for causal_conv1d_cp"
|
| 249 |
assert cp_context.cu_seqlens is not None, "cu_seqlens must be provided for causal_conv1d_cp"
|
| 250 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 251 |
chunk_size = chunk_size or 64
|
| 252 |
if chunk_indices is None:
|
| 253 |
-
chunk_indices = prepare_chunk_indices(
|
|
|
|
|
|
|
|
|
|
|
|
|
| 254 |
|
| 255 |
-
return CausalConv1dFunctionCP.apply(
|
| 256 |
-
x, weight, bias, activation,
|
| 257 |
-
chunk_indices, cp_context, chunk_size, backend
|
| 258 |
-
)
|
|
|
|
| 8 |
import torch
|
| 9 |
import torch.distributed as dist
|
| 10 |
|
| 11 |
+
from ...ops.cp import FLACPContext, all_gather_into_tensor, conv_cp_send_recv_bwd, conv_cp_send_recv_fwd
|
| 12 |
+
from ...ops.utils import prepare_chunk_indices
|
| 13 |
|
| 14 |
|
| 15 |
class CausalConv1dFunctionCP(torch.autograd.Function):
|
|
|
|
| 36 |
"""Prepare initial_state for CP forward pass by communicating with previous rank.
|
| 37 |
|
| 38 |
Args:
|
| 39 |
+
x (torch.Tensor):
|
| 40 |
+
Input tensor of shape [1, T, D]
|
| 41 |
+
weight (torch.Tensor):
|
| 42 |
+
Weight tensor of shape [D, W]
|
| 43 |
+
cu_seqlens (torch.Tensor | None):
|
| 44 |
+
Cumulative sequence lengths
|
| 45 |
+
context (FLACPContext):
|
| 46 |
+
CP context
|
| 47 |
+
group (dist.ProcessGroup | None):
|
| 48 |
+
Process group for communication
|
| 49 |
|
| 50 |
Returns:
|
| 51 |
+
initial_state (torch.Tensor | None):
|
| 52 |
+
Initial state tensor of shape [N, D, W] or None
|
| 53 |
"""
|
| 54 |
+
W = weight.shape[-1] # weight: [D, W]
|
| 55 |
+
if group is None or W == 1:
|
| 56 |
return None
|
| 57 |
|
|
|
|
| 58 |
D = weight.shape[0]
|
| 59 |
initial_state = None
|
| 60 |
+
if context.layout == 'zigzag':
|
| 61 |
+
world_size = dist.get_world_size(group)
|
| 62 |
+
rank = dist.get_rank(group)
|
| 63 |
+
part_len = context.part_len
|
| 64 |
+
assert part_len >= W - 1, (
|
| 65 |
+
f"zigzag CP requires part_len ({part_len}) >= conv1d_kernel_size - 1 ({W - 1}); "
|
| 66 |
+
"increase total tokens or reduce world size"
|
| 67 |
+
)
|
| 68 |
+
assert x.dim() == 3 and x.shape[0] == 1, f"CP requires [1, T, D], got {x.shape}"
|
| 69 |
+
x_2d = x.squeeze(0) # [T, D]
|
| 70 |
+
# last W-1 tokens of each chain part (front, back)
|
| 71 |
+
tails = torch.stack([x_2d[part_len - (W - 1): part_len], x_2d[-(W - 1):]])
|
| 72 |
+
gathered, _ = all_gather_into_tensor(tails, group=group)
|
| 73 |
+
# chain order: front parts of ranks 0..W-1, then back parts of ranks W-1..0
|
| 74 |
+
slots = torch.cat([gathered[:, 0], gathered[:, 1].flip(0)])
|
| 75 |
+
N = len(cu_seqlens) - 1
|
| 76 |
+
initial_state = torch.zeros(N, D, W, device=x.device, dtype=x.dtype)
|
| 77 |
+
for part, row in enumerate((0, context.front_num_seqs)):
|
| 78 |
+
if not context.is_first_by_part[part]:
|
| 79 |
+
valid_len = min(W - 1, context.pre_num_conv_tokens_by_part[part])
|
| 80 |
+
if valid_len > 0:
|
| 81 |
+
chain_pos = rank if part == 0 else 2 * world_size - 1 - rank
|
| 82 |
+
initial_state[row, :, -valid_len:] = slots[chain_pos - 1][-valid_len:].T
|
| 83 |
+
return initial_state
|
| 84 |
if not context.is_first_rank:
|
| 85 |
+
# non-first rank needs initial_state
|
| 86 |
assert x.dim() == 3 and x.shape[0] == 1, f"CP requires [1, T, D], got {x.shape}"
|
| 87 |
x_2d = x.squeeze(0) # [T, D]
|
| 88 |
tails = x_2d[-(W-1):].contiguous() # [W-1, D]
|
| 89 |
heads = conv_cp_send_recv_fwd(tails, group) # [W-1, D]
|
| 90 |
+
# construct initial_state: [N, D, W]
|
| 91 |
N = len(cu_seqlens) - 1
|
| 92 |
initial_state = torch.zeros(N, D, W, device=x.device, dtype=x.dtype)
|
| 93 |
valid_len = min(W - 1, context.pre_num_conv_tokens)
|
|
|
|
| 95 |
# heads[-valid_len:]: [valid_len, D] -> [D, valid_len]
|
| 96 |
initial_state[0, :, -valid_len:] = heads[-valid_len:].T
|
| 97 |
else:
|
| 98 |
+
# first rank also needs to participate in communication (send tails)
|
| 99 |
x_2d = x.squeeze(0)
|
| 100 |
tails = x_2d[-(W-1):].contiguous()
|
| 101 |
+
# send but don't use
|
| 102 |
+
_ = conv_cp_send_recv_fwd(tails, group)
|
| 103 |
|
| 104 |
return initial_state
|
| 105 |
|
|
|
|
| 109 |
dh0: torch.Tensor | None,
|
| 110 |
W: int,
|
| 111 |
group: dist.ProcessGroup | None,
|
| 112 |
+
cp_context: FLACPContext,
|
|
|
|
| 113 |
) -> None:
|
| 114 |
"""Correct dx gradients for CP backward pass by communicating with next rank.
|
| 115 |
|
| 116 |
Args:
|
| 117 |
+
dx (torch.Tensor):
|
| 118 |
+
Gradient tensor to be corrected, shape [1, T, D]
|
| 119 |
+
dh0 (torch.Tensor | None):
|
| 120 |
+
Gradient w.r.t. initial_state, shape [N, D, W] or None
|
| 121 |
+
W (int):
|
| 122 |
+
Kernel size
|
| 123 |
+
group (dist.ProcessGroup | None):
|
| 124 |
+
Process group for communication
|
| 125 |
+
cp_context (FLACPContext):
|
| 126 |
+
CP context
|
| 127 |
"""
|
| 128 |
+
if group is None or W == 1:
|
| 129 |
return
|
| 130 |
|
| 131 |
D = dx.shape[-1]
|
| 132 |
+
if cp_context.layout == 'zigzag':
|
| 133 |
+
world_size = dist.get_world_size(group)
|
| 134 |
+
rank = dist.get_rank(group)
|
| 135 |
+
part_len = cp_context.part_len
|
| 136 |
+
# dh0 rows for chain-first parts stay zero: their forward initial_state was zeros
|
| 137 |
+
d_initial_state = torch.zeros(2, W - 1, D, device=dx.device, dtype=dx.dtype)
|
| 138 |
+
for part, row in enumerate((0, cp_context.front_num_seqs)):
|
| 139 |
+
if not cp_context.is_first_by_part[part]:
|
| 140 |
+
valid_len = min(W - 1, cp_context.pre_num_conv_tokens_by_part[part])
|
| 141 |
+
if valid_len > 0:
|
| 142 |
+
d_initial_state[part, -valid_len:] = dh0[row, :, -valid_len:].T
|
| 143 |
+
gathered, _ = all_gather_into_tensor(d_initial_state, group=group)
|
| 144 |
+
# chain order: front parts of ranks 0..W-1, then back parts of ranks W-1..0
|
| 145 |
+
slots = torch.cat([gathered[:, 0], gathered[:, 1].flip(0)])
|
| 146 |
+
# the front part's chain successor is the next rank's front or own back part
|
| 147 |
+
dx[0, part_len - (W - 1): part_len, :].add_(slots[rank + 1])
|
| 148 |
+
# the back part's successor exists unless it is chain-last (rank 0)
|
| 149 |
+
if rank > 0:
|
| 150 |
+
dx[0, -(W - 1):, :].add_(slots[2 * world_size - rank])
|
| 151 |
+
return
|
| 152 |
# dh0: [N, D, W] or None
|
| 153 |
# We only care about the first sequence's initial_state gradient
|
| 154 |
if dh0 is not None:
|
|
|
|
| 156 |
# previous rank. The forward fills only the last valid_len positions
|
| 157 |
# of initial_state; gradients for the remaining (zero-padded) positions
|
| 158 |
# must not flow back, otherwise they leak into unrelated sequences.
|
| 159 |
+
valid_len = min(W - 1, cp_context.pre_num_conv_tokens)
|
| 160 |
d_initial_state = torch.zeros(W-1, D, device=dx.device, dtype=dx.dtype)
|
| 161 |
if valid_len > 0:
|
| 162 |
d_initial_state[-valid_len:] = dh0[0, :, -valid_len:].T
|
| 163 |
else:
|
| 164 |
# dh0 is None only when this is the first rank (no initial_state needed)
|
| 165 |
+
assert cp_context.is_first_rank, "dh0 should not be None when is_first_rank=False"
|
| 166 |
d_initial_state = torch.zeros(W-1, D, device=dx.device, dtype=dx.dtype)
|
| 167 |
# Sync communication: send d_initial_state to previous rank, receive from next rank
|
| 168 |
recv_d_init = conv_cp_send_recv_bwd(d_initial_state, group) # [W-1, D]
|
|
|
|
| 180 |
cp_context: FLACPContext | None,
|
| 181 |
chunk_size: int | None,
|
| 182 |
backend: str = 'triton',
|
| 183 |
+
residual: torch.Tensor | None = None,
|
| 184 |
+
) -> torch.Tensor:
|
| 185 |
+
# import here to avoid circular dependency
|
| 186 |
+
from ...modules.causal_conv1d import causal_conv1d_fwd
|
| 187 |
|
| 188 |
if cp_context is None:
|
| 189 |
raise ValueError("cp_context must be provided for CausalConv1dFunctionCP")
|
|
|
|
| 191 |
cu_seqlens_cpu = cp_context.cu_seqlens_cpu
|
| 192 |
group = cp_context.group
|
| 193 |
|
| 194 |
+
# get kernel_size
|
| 195 |
W = weight.shape[-1] # weight: [D, W]
|
| 196 |
+
# prepare initial_state for CP
|
| 197 |
initial_state = CausalConv1dFunctionCP._prepare_initial_state_for_cp(
|
| 198 |
x=x,
|
| 199 |
weight=weight,
|
|
|
|
| 202 |
group=group,
|
| 203 |
)
|
| 204 |
|
| 205 |
+
ctx.save_for_backward(x, weight, bias, residual, initial_state)
|
| 206 |
ctx.activation = activation
|
| 207 |
ctx.cu_seqlens = cu_seqlens
|
| 208 |
ctx.cu_seqlens_cpu = cu_seqlens_cpu
|
|
|
|
| 210 |
ctx.chunk_size = chunk_size
|
| 211 |
ctx.group = group
|
| 212 |
ctx.W = W
|
| 213 |
+
ctx.cp_context = cp_context
|
|
|
|
| 214 |
|
| 215 |
+
# call original forward
|
| 216 |
y, _ = causal_conv1d_fwd(
|
| 217 |
x=x,
|
| 218 |
weight=weight,
|
| 219 |
bias=bias,
|
| 220 |
+
residual=residual,
|
| 221 |
initial_state=initial_state,
|
| 222 |
output_final_state=False,
|
| 223 |
activation=activation,
|
| 224 |
cu_seqlens=cu_seqlens,
|
| 225 |
cu_seqlens_cpu=cu_seqlens_cpu,
|
| 226 |
chunk_indices=chunk_indices,
|
| 227 |
+
chunk_size=chunk_size,
|
| 228 |
)
|
| 229 |
|
| 230 |
return y
|
| 231 |
|
| 232 |
@staticmethod
|
| 233 |
+
def backward(ctx, dy: torch.Tensor) -> tuple[torch.Tensor | None, ...]:
|
| 234 |
+
# import here to avoid circular dependency
|
| 235 |
+
from ...modules.causal_conv1d import causal_conv1d_bwd
|
| 236 |
|
| 237 |
+
x, weight, bias, residual, initial_state = ctx.saved_tensors
|
| 238 |
group = ctx.group
|
| 239 |
W = ctx.W
|
| 240 |
|
| 241 |
+
# call original backward
|
| 242 |
+
dx, dw, db, dr, dh0 = causal_conv1d_bwd(
|
| 243 |
x=x,
|
| 244 |
dy=dy,
|
| 245 |
dht=None,
|
| 246 |
weight=weight,
|
| 247 |
bias=bias,
|
| 248 |
+
residual=residual,
|
| 249 |
initial_state=initial_state,
|
| 250 |
activation=ctx.activation,
|
| 251 |
cu_seqlens=ctx.cu_seqlens,
|
| 252 |
cu_seqlens_cpu=ctx.cu_seqlens_cpu,
|
| 253 |
chunk_indices=ctx.chunk_indices,
|
| 254 |
+
chunk_size=ctx.chunk_size,
|
| 255 |
)
|
| 256 |
|
| 257 |
+
# correct dx gradients for CP
|
| 258 |
+
CausalConv1dFunctionCP._correct_dx_for_cp(dx=dx, dh0=dh0, W=W, group=group, cp_context=ctx.cp_context)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 259 |
|
| 260 |
+
return dx, dw, db, None, None, None, None, None, dr
|
| 261 |
|
| 262 |
|
| 263 |
def causal_conv1d_cp(
|
|
|
|
| 269 |
cp_context: FLACPContext | None = None,
|
| 270 |
chunk_size: int | None = None,
|
| 271 |
backend: str = 'triton',
|
| 272 |
+
residual: torch.Tensor | None = None,
|
| 273 |
+
) -> torch.Tensor:
|
| 274 |
+
"""Apply causal convolution with cross-rank history and gradient exchange.
|
|
|
|
|
|
|
|
|
|
|
|
|
| 275 |
|
| 276 |
Args:
|
| 277 |
+
x (torch.Tensor):
|
| 278 |
+
Local input of shape `[1, T, D]`.
|
| 279 |
+
weight (torch.Tensor):
|
| 280 |
+
Convolution weights of shape `[D, W]`.
|
| 281 |
+
bias (torch.Tensor, Optional):
|
| 282 |
+
Bias of shape `[D]`. Default: `None`.
|
| 283 |
+
activation (str, Optional):
|
| 284 |
+
Output activation: `None`, `silu`, or `swish`. Default: `None`.
|
| 285 |
+
chunk_indices (torch.Tensor, Optional):
|
| 286 |
+
Precomputed chunk indices for the Triton backend. Default: `None`.
|
| 287 |
+
cp_context (FLACPContext, Optional):
|
| 288 |
+
Required CP context with cumulative sequence lengths and convolution width. Default: `None`.
|
| 289 |
+
chunk_size (int, Optional):
|
| 290 |
+
Triton chunk size; `None` selects 64. Default: `None`.
|
| 291 |
+
backend (str, Optional):
|
| 292 |
+
Convolution backend: `triton`, `cuda`, or `mix`. `mix` retains the Triton CP path.
|
| 293 |
+
CUDA requires contiguous layout, width 2–4, and at least `W - 1` tokens per rank. Default: `'triton'`.
|
| 294 |
+
residual (torch.Tensor, Optional):
|
| 295 |
+
Residual added to the output, of shape `[1, T, D]`. Default: `None`.
|
| 296 |
+
|
| 297 |
+
Returns:
|
| 298 |
+
torch.Tensor:
|
| 299 |
+
Local output of shape `[1, T, D]`.
|
| 300 |
"""
|
| 301 |
if cp_context is None:
|
| 302 |
raise ValueError("cp_context must be provided for causal_conv1d_cp")
|
| 303 |
|
| 304 |
assert cp_context.conv1d_kernel_size is not None, "conv1d_kernel_size must be provided for causal_conv1d_cp"
|
| 305 |
assert cp_context.cu_seqlens is not None, "cu_seqlens must be provided for causal_conv1d_cp"
|
| 306 |
+
if backend == 'mix':
|
| 307 |
+
backend = 'triton'
|
| 308 |
+
if backend not in ('triton', 'cuda'):
|
| 309 |
+
raise ValueError(f"Unsupported CP convolution backend: {backend!r}; expected 'triton', 'cuda', or 'mix'")
|
| 310 |
+
if backend == 'cuda':
|
| 311 |
+
from ...modules.causal_conv1d.backends.cuda.cp import causal_conv1d_cuda_cp
|
| 312 |
+
|
| 313 |
+
return causal_conv1d_cuda_cp(
|
| 314 |
+
x=x,
|
| 315 |
+
weight=weight,
|
| 316 |
+
bias=bias,
|
| 317 |
+
residual=residual,
|
| 318 |
+
activation=activation,
|
| 319 |
+
cp_context=cp_context,
|
| 320 |
+
)
|
| 321 |
+
|
| 322 |
chunk_size = chunk_size or 64
|
| 323 |
if chunk_indices is None:
|
| 324 |
+
chunk_indices = prepare_chunk_indices(
|
| 325 |
+
cu_seqlens=cp_context.cu_seqlens,
|
| 326 |
+
chunk_size=chunk_size,
|
| 327 |
+
cu_seqlens_cpu=cp_context.cu_seqlens_cpu,
|
| 328 |
+
)
|
| 329 |
|
| 330 |
+
return CausalConv1dFunctionCP.apply(x, weight, bias, activation, chunk_indices, cp_context, chunk_size, backend, residual)
|
|
|
|
|
|
|
|
|
build/torch-cuda/modules/{conv/triton/kernels.py → causal_conv1d/ops.py}
RENAMED
|
@@ -5,13 +5,27 @@
|
|
| 5 |
# For a list of all contributors, visit:
|
| 6 |
# https://github.com/fla-org/flash-linear-attention/graphs/contributors
|
| 7 |
|
|
|
|
|
|
|
|
|
|
| 8 |
import torch
|
|
|
|
| 9 |
import triton
|
| 10 |
import triton.language as tl
|
| 11 |
from einops import rearrange
|
| 12 |
|
| 13 |
-
from ...
|
| 14 |
-
from ....
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 15 |
|
| 16 |
NUM_WARPS_AUTOTUNE = [2, 4, 8, 16] if IS_AMD else [4, 8, 16, 32]
|
| 17 |
STATIC_WARPS = 32 if not IS_AMD else 16
|
|
@@ -30,7 +44,7 @@ STATIC_WARPS = 32 if not IS_AMD else 16
|
|
| 30 |
for BD in [16, 32, 64, 128]
|
| 31 |
for num_warps in NUM_WARPS_AUTOTUNE
|
| 32 |
],
|
| 33 |
-
key=['D', 'W'
|
| 34 |
**autotune_cache_kwargs,
|
| 35 |
)
|
| 36 |
@triton.jit
|
|
@@ -53,7 +67,6 @@ def causal_conv1d_fwd_kernel(
|
|
| 53 |
BT: tl.constexpr,
|
| 54 |
BW: tl.constexpr,
|
| 55 |
BD: tl.constexpr,
|
| 56 |
-
NB: tl.constexpr,
|
| 57 |
ACTIVATION: tl.constexpr,
|
| 58 |
HAS_WEIGHT: tl.constexpr,
|
| 59 |
HAS_BIAS: tl.constexpr,
|
|
@@ -74,9 +87,11 @@ def causal_conv1d_fwd_kernel(
|
|
| 74 |
p_x = x + tl.cast(i_b, tl.int64) * stride_x_n
|
| 75 |
|
| 76 |
o_d = i_d * BD + tl.arange(0, BD)
|
|
|
|
| 77 |
o_w = tl.arange(0, BW) + W - BW
|
| 78 |
m_d = o_d < D
|
| 79 |
m_w = o_w >= 0
|
|
|
|
| 80 |
|
| 81 |
if HAS_WEIGHT:
|
| 82 |
# [BD, BW]
|
|
@@ -85,33 +100,31 @@ def causal_conv1d_fwd_kernel(
|
|
| 85 |
b_y = tl.zeros((BT, BD), dtype=tl.float32)
|
| 86 |
if not USE_INITIAL_STATE:
|
| 87 |
for i_w in tl.static_range(-W + 1, 1):
|
| 88 |
-
|
|
|
|
| 89 |
# [BT, BD]
|
| 90 |
-
b_yi = tl.load(p_yi,
|
| 91 |
if HAS_WEIGHT:
|
| 92 |
b_yi *= tl.sum(b_w * (o_w == (i_w + W - 1)), 1)
|
| 93 |
b_y += b_yi
|
| 94 |
elif i_t * BT >= W:
|
| 95 |
-
#
|
| 96 |
for i_w in tl.static_range(-W + 1, 1):
|
| 97 |
-
|
|
|
|
| 98 |
# [BT, BD]
|
| 99 |
-
b_yi = tl.load(p_yi,
|
| 100 |
if HAS_WEIGHT:
|
| 101 |
b_yi *= tl.sum(b_w * (o_w == (i_w + W - 1)), 1)
|
| 102 |
b_y += b_yi
|
| 103 |
else:
|
| 104 |
-
o_t = i_t * BT + tl.arange(0, BT)
|
| 105 |
for i_w in tl.static_range(-W + 1, 1):
|
| 106 |
o_x = o_t + i_w
|
| 107 |
m_x = ((o_x >= 0) & (o_x < T))[:, None] & m_d
|
| 108 |
m_c = ((o_x + W >= 0) & (o_x < 0))[:, None] & m_d
|
| 109 |
|
| 110 |
-
b_yi = tl.load(
|
| 111 |
-
p_x + o_x[:, None] * stride_x_t + o_d * stride_x_d,
|
| 112 |
-
mask=m_x,
|
| 113 |
-
other=0
|
| 114 |
-
).to(tl.float32)
|
| 115 |
|
| 116 |
b_yi += tl.load(initial_state + i_n * D*W + o_d * W + (o_x + W)[:, None], mask=m_c, other=0).to(tl.float32)
|
| 117 |
|
|
@@ -126,12 +139,12 @@ def causal_conv1d_fwd_kernel(
|
|
| 126 |
b_y = b_y * tl.sigmoid(b_y)
|
| 127 |
|
| 128 |
if HAS_RESIDUAL:
|
| 129 |
-
p_residual =
|
| 130 |
-
b_residual = tl.load(p_residual,
|
| 131 |
b_y += b_residual
|
| 132 |
|
| 133 |
-
p_y =
|
| 134 |
-
tl.store(p_y, tl.cast(b_y, dtype=p_y.dtype.element_ty, fp_downcast_rounding='rtne'),
|
| 135 |
|
| 136 |
|
| 137 |
@triton.heuristics({
|
|
@@ -145,9 +158,9 @@ def causal_conv1d_fwd_kernel(
|
|
| 145 |
configs=[
|
| 146 |
triton.Config({'BD': BD}, num_warps=num_warps)
|
| 147 |
for BD in [16, 32, 64, 128]
|
| 148 |
-
for num_warps in
|
| 149 |
],
|
| 150 |
-
key=['D', 'W'
|
| 151 |
**autotune_cache_kwargs,
|
| 152 |
)
|
| 153 |
@triton.jit
|
|
@@ -165,21 +178,20 @@ def causal_conv1d_bwd_kernel(
|
|
| 165 |
chunk_indices,
|
| 166 |
B,
|
| 167 |
T,
|
| 168 |
-
stride_x_n,
|
| 169 |
-
stride_x_t,
|
| 170 |
-
stride_x_d,
|
| 171 |
-
stride_dx_n,
|
| 172 |
-
stride_dx_t,
|
| 173 |
-
stride_dx_d,
|
| 174 |
-
stride_dy_n,
|
| 175 |
-
stride_dy_t,
|
| 176 |
-
stride_dy_d,
|
| 177 |
D: tl.constexpr,
|
| 178 |
W: tl.constexpr,
|
| 179 |
BT: tl.constexpr,
|
| 180 |
BW: tl.constexpr,
|
| 181 |
BD: tl.constexpr,
|
| 182 |
-
NB: tl.constexpr,
|
| 183 |
ACTIVATION: tl.constexpr,
|
| 184 |
HAS_WEIGHT: tl.constexpr,
|
| 185 |
HAS_BIAS: tl.constexpr,
|
|
@@ -206,13 +218,15 @@ def causal_conv1d_bwd_kernel(
|
|
| 206 |
p_dy = dy + tl.cast(i_b, tl.int64) * stride_dy_n
|
| 207 |
|
| 208 |
o_d = i_d * BD + tl.arange(0, BD)
|
|
|
|
| 209 |
o_w = tl.arange(0, BW) + W - BW
|
| 210 |
m_d = o_d < D
|
| 211 |
m_w = o_w >= 0
|
|
|
|
| 212 |
|
| 213 |
if HAS_WEIGHT:
|
| 214 |
-
p_x =
|
| 215 |
-
b_x = tl.load(p_x,
|
| 216 |
# [BD, BW]
|
| 217 |
b_w = tl.load(weight + o_d[:, None] * W + o_w, mask=m_d[:, None] & m_w, other=0)
|
| 218 |
|
|
@@ -222,13 +236,13 @@ def causal_conv1d_bwd_kernel(
|
|
| 222 |
|
| 223 |
if not USE_FINAL_STATE and not USE_INITIAL_STATE:
|
| 224 |
for i_w in tl.static_range(0, W):
|
| 225 |
-
|
| 226 |
-
|
| 227 |
# [BT, BD]
|
| 228 |
-
b_dy = tl.load(p_dy_blk,
|
| 229 |
if ACTIVATION == 'swish' or ACTIVATION == 'silu':
|
| 230 |
-
p_y =
|
| 231 |
-
b_y = tl.load(p_y,
|
| 232 |
b_ys = tl.sigmoid(b_y)
|
| 233 |
b_dy = b_dy * b_ys * (1 + b_y * (1 - b_ys))
|
| 234 |
b_wdy = b_dy
|
|
@@ -242,15 +256,15 @@ def causal_conv1d_bwd_kernel(
|
|
| 242 |
b_db += tl.sum(b_dy, 0)
|
| 243 |
b_dx += b_wdy
|
| 244 |
elif i_t * BT >= W:
|
| 245 |
-
#
|
| 246 |
for i_w in tl.static_range(0, W):
|
| 247 |
-
|
| 248 |
-
|
| 249 |
# [BT, BD]
|
| 250 |
-
b_dy = tl.load(p_dy_blk,
|
| 251 |
if ACTIVATION == 'swish' or ACTIVATION == 'silu':
|
| 252 |
-
p_y =
|
| 253 |
-
b_y = tl.load(p_y,
|
| 254 |
b_ys = tl.sigmoid(b_y)
|
| 255 |
b_dy = b_dy * b_ys * (1 + b_y * (1 - b_ys))
|
| 256 |
b_wdy = b_dy
|
|
@@ -264,38 +278,42 @@ def causal_conv1d_bwd_kernel(
|
|
| 264 |
b_db += tl.sum(b_dy, 0)
|
| 265 |
b_dx += b_wdy
|
| 266 |
else:
|
| 267 |
-
|
| 268 |
-
o_t = i_t * BT + tl.arange(0, BT)
|
| 269 |
for i_w in tl.static_range(0, W):
|
| 270 |
-
|
| 271 |
-
|
| 272 |
-
b_dy_shift = tl.load(p_dy_blk,
|
| 273 |
if ACTIVATION == 'swish' or ACTIVATION == 'silu':
|
| 274 |
-
p_y =
|
| 275 |
-
b_y_shift = tl.load(p_y,
|
| 276 |
b_ys = tl.sigmoid(b_y_shift)
|
| 277 |
b_dy_shift = b_dy_shift * b_ys * (1 + b_y_shift * (1 - b_ys))
|
| 278 |
if HAS_WEIGHT:
|
| 279 |
-
# gradient comes from x:sum_t dy[t+i_w] * x[t]
|
| 280 |
b_dw = tl.sum(b_dy_shift * b_x, 0)
|
| 281 |
-
# index of cache:c = W - i_w + t
|
| 282 |
if USE_INITIAL_STATE:
|
| 283 |
mask_head_rows = (o_t < i_w) & (o_t < T)
|
| 284 |
-
|
| 285 |
-
|
| 286 |
-
|
|
|
|
|
|
|
| 287 |
if ACTIVATION == 'swish' or ACTIVATION == 'silu':
|
| 288 |
-
# use
|
| 289 |
-
b_y_head = tl.load(
|
| 290 |
-
|
|
|
|
|
|
|
|
|
|
| 291 |
b_ys_head = tl.sigmoid(b_y_head)
|
| 292 |
b_dy_head = b_dy_head * b_ys_head * (1 + b_y_head * (1 - b_ys_head))
|
| 293 |
o_c = W - i_w + o_t
|
| 294 |
# index 0 is padding 0
|
| 295 |
mask_c = (mask_head_rows & (o_c >= 1) & (o_c < W))
|
| 296 |
-
b_xc = tl.load(
|
| 297 |
-
|
| 298 |
-
|
|
|
|
|
|
|
| 299 |
b_dw += tl.sum(b_dy_head * b_xc, 0)
|
| 300 |
tl.store(dw + i_tg * D * W + o_d * W + W - i_w - 1, b_dw.to(dw.dtype.element_ty), mask=m_d)
|
| 301 |
|
|
@@ -312,9 +330,11 @@ def causal_conv1d_bwd_kernel(
|
|
| 312 |
if i_t * BT + BT >= T-W:
|
| 313 |
start_tok = max(0, T - (W - 1))
|
| 314 |
offset = i_t * BT + tl.arange(0, BT)
|
| 315 |
-
tok_idx = offset - start_tok
|
| 316 |
mask = (offset >= start_tok) & (offset < T)
|
| 317 |
-
|
|
|
|
|
|
|
|
|
|
| 318 |
dht_off = i_n * D * W + o_d[None, :] * W + w_idx[:, None]
|
| 319 |
b_dht = tl.load(dht + dht_off, mask=mask[:, None] & m_d[None, :], other=0.).to(tl.float32)
|
| 320 |
b_dx += b_dht
|
|
@@ -324,8 +344,8 @@ def causal_conv1d_bwd_kernel(
|
|
| 324 |
else:
|
| 325 |
p_dx = dx + tl.cast(i_b, tl.int64) * stride_dx_n
|
| 326 |
|
| 327 |
-
p_dx =
|
| 328 |
-
tl.store(p_dx, tl.cast(b_dx, dtype=p_dx.dtype.element_ty, fp_downcast_rounding='rtne'),
|
| 329 |
|
| 330 |
|
| 331 |
@triton.heuristics({
|
|
@@ -352,10 +372,10 @@ def causal_conv1d_update_kernel(
|
|
| 352 |
y,
|
| 353 |
weight,
|
| 354 |
bias,
|
| 355 |
-
stride_x_n,
|
| 356 |
-
stride_x_d,
|
| 357 |
-
stride_y_n,
|
| 358 |
-
stride_y_d,
|
| 359 |
D: tl.constexpr,
|
| 360 |
W: tl.constexpr,
|
| 361 |
BD: tl.constexpr,
|
|
@@ -366,7 +386,9 @@ def causal_conv1d_update_kernel(
|
|
| 366 |
HAS_BIAS: tl.constexpr,
|
| 367 |
HAS_RESIDUAL: tl.constexpr,
|
| 368 |
):
|
| 369 |
-
|
|
|
|
|
|
|
| 370 |
|
| 371 |
o_d = i_d * BD + tl.arange(0, BD)
|
| 372 |
o_w = tl.arange(0, BW)
|
|
@@ -379,18 +401,9 @@ def causal_conv1d_update_kernel(
|
|
| 379 |
b_cache = tl.zeros((BD, BW), dtype=tl.float32)
|
| 380 |
|
| 381 |
if USE_INITIAL_STATE:
|
| 382 |
-
|
| 383 |
-
|
| 384 |
-
cache + i_n * D*W,
|
| 385 |
-
shape=(D, W),
|
| 386 |
-
strides=(W, 1),
|
| 387 |
-
offsets=(i_d * BD, 1),
|
| 388 |
-
block_shape=(BD, BW),
|
| 389 |
-
order=(1, 0)
|
| 390 |
-
)
|
| 391 |
-
b_cache = tl.load(p_cache_read, boundary_check=(0, 1)).to(tl.float32)
|
| 392 |
|
| 393 |
-
# 3. Fill x to the last position
|
| 394 |
m_update = o_w == (W - 1)
|
| 395 |
b_cache = tl.where(m_update[None, :], b_x[:, None], b_cache)
|
| 396 |
|
|
@@ -409,24 +422,24 @@ def causal_conv1d_update_kernel(
|
|
| 409 |
if HAS_RESIDUAL:
|
| 410 |
b_y += tl.load(residual + i_n * D + o_d, mask=m_d, other=0)
|
| 411 |
|
| 412 |
-
tl.store(
|
| 413 |
-
|
|
|
|
|
|
|
|
|
|
| 414 |
|
| 415 |
if USE_INITIAL_STATE:
|
| 416 |
-
p_cache_write =
|
| 417 |
-
|
| 418 |
-
|
| 419 |
-
|
| 420 |
-
|
| 421 |
-
block_shape=(BD, BW),
|
| 422 |
-
order=(1, 0)
|
| 423 |
)
|
| 424 |
-
tl.store(p_cache_write, tl.cast(b_cache, dtype=cache.dtype.element_ty,
|
| 425 |
-
fp_downcast_rounding='rtne'), boundary_check=(0, 1))
|
| 426 |
|
| 427 |
|
| 428 |
@triton.heuristics({
|
| 429 |
'USE_ACTIVATION': lambda args: args['y'] is not None,
|
|
|
|
| 430 |
'IS_VARLEN': lambda args: args['cu_seqlens'] is not None,
|
| 431 |
})
|
| 432 |
@triton.jit
|
|
@@ -435,69 +448,75 @@ def compute_dh0_kernel(
|
|
| 435 |
y,
|
| 436 |
weight,
|
| 437 |
dh0,
|
|
|
|
| 438 |
cu_seqlens,
|
| 439 |
stride_dy_n,
|
| 440 |
stride_dy_t,
|
|
|
|
| 441 |
T,
|
| 442 |
D: tl.constexpr,
|
| 443 |
W: tl.constexpr,
|
| 444 |
BD: tl.constexpr,
|
| 445 |
USE_ACTIVATION: tl.constexpr,
|
|
|
|
| 446 |
IS_VARLEN: tl.constexpr,
|
| 447 |
):
|
| 448 |
"""
|
| 449 |
Compute dh0 (gradient w.r.t. initial_state) in a separate kernel.
|
| 450 |
This avoids Triton compiler bugs on some architectures (e.g., GB200).
|
| 451 |
|
| 452 |
-
Grid: (cdiv(D, BD)
|
| 453 |
"""
|
| 454 |
-
|
|
|
|
|
|
|
| 455 |
|
| 456 |
-
# Get sequence boundaries
|
| 457 |
if IS_VARLEN:
|
| 458 |
bos = tl.load(cu_seqlens + i_n).to(tl.int64)
|
| 459 |
eos = tl.load(cu_seqlens + i_n + 1).to(tl.int64)
|
| 460 |
seq_len = eos - bos
|
| 461 |
-
#
|
| 462 |
dy_base = dy + bos * stride_dy_t
|
| 463 |
else:
|
| 464 |
seq_len = T
|
| 465 |
-
#
|
| 466 |
dy_base = dy + tl.cast(i_n, tl.int64) * stride_dy_n
|
| 467 |
|
| 468 |
o_d = i_d * BD + tl.arange(0, BD)
|
| 469 |
m_d = o_d < D
|
| 470 |
|
| 471 |
-
# For each i_w in [1, W), compute dh0[i_n, :, i_w]
|
| 472 |
for i_w in tl.static_range(1, W):
|
| 473 |
b_dh0 = tl.zeros([BD], dtype=tl.float32)
|
| 474 |
|
| 475 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 476 |
for t in tl.static_range(0, W - 1):
|
| 477 |
if t < i_w:
|
| 478 |
w_idx = i_w - 1 - t
|
| 479 |
|
| 480 |
-
|
| 481 |
-
p_dy = dy_base + t * stride_dy_t + o_d
|
| 482 |
m_t = (t < seq_len) & m_d
|
| 483 |
b_dy = tl.load(p_dy, mask=m_t, other=0).to(tl.float32)
|
| 484 |
|
| 485 |
if USE_ACTIVATION:
|
|
|
|
| 486 |
if IS_VARLEN:
|
| 487 |
-
p_y = y + bos *
|
| 488 |
else:
|
| 489 |
-
p_y = y + tl.cast(i_n, tl.int64) *
|
| 490 |
b_y = tl.load(p_y, mask=m_t, other=0).to(tl.float32)
|
| 491 |
b_ys = tl.sigmoid(b_y)
|
| 492 |
b_dy = b_dy * b_ys * (1 + b_y * (1 - b_ys))
|
| 493 |
|
| 494 |
-
# Get weight[:, w_idx]
|
| 495 |
b_w_col = tl.load(weight + o_d * W + w_idx, mask=m_d, other=0).to(tl.float32)
|
| 496 |
|
| 497 |
-
# Accumulate
|
| 498 |
b_dh0 += tl.where(m_t, b_dy * b_w_col, 0)
|
| 499 |
|
| 500 |
-
# Store dh0[i_n, :, i_w]
|
| 501 |
p_dh0 = dh0 + i_n * D * W + o_d * W + i_w
|
| 502 |
tl.store(p_dh0, b_dh0.to(dh0.dtype.element_ty), mask=m_d)
|
| 503 |
|
|
@@ -523,9 +542,11 @@ def causal_conv1d_states_fwd_kernel(
|
|
| 523 |
USE_INITIAL_STATE: tl.constexpr,
|
| 524 |
IS_VARLEN: tl.constexpr,
|
| 525 |
):
|
| 526 |
-
|
|
|
|
|
|
|
| 527 |
|
| 528 |
-
#
|
| 529 |
o_d = i_d * BD + tl.arange(0, BD)
|
| 530 |
m_d = o_d < D
|
| 531 |
|
|
@@ -538,10 +559,11 @@ def causal_conv1d_states_fwd_kernel(
|
|
| 538 |
seq_len = T
|
| 539 |
p_x = x + tl.cast(i_n, tl.int64) * stride_x_n
|
| 540 |
|
| 541 |
-
|
|
|
|
| 542 |
|
| 543 |
-
#
|
| 544 |
-
b_x = tl.load(p_x,
|
| 545 |
|
| 546 |
if USE_INITIAL_STATE:
|
| 547 |
if seq_len < BW:
|
|
@@ -554,21 +576,245 @@ def causal_conv1d_states_fwd_kernel(
|
|
| 554 |
b_cache = tl.load(p_init, mask=mask_init, other=0)
|
| 555 |
b_x += b_cache
|
| 556 |
|
| 557 |
-
# final_state: [N, D, W]
|
| 558 |
-
#
|
| 559 |
o_w = W - BW + tl.arange(0, BW)
|
| 560 |
|
| 561 |
# o_d[:, None] -> [BD, 1]
|
| 562 |
# o_w[None, :] -> [1, BW]
|
| 563 |
-
#
|
| 564 |
p_final = final_state + tl.cast(i_n, tl.int64) * D*W + o_d[:, None] * W + o_w[None, :]
|
| 565 |
|
| 566 |
-
#
|
| 567 |
m_final = m_d[:, None] & (o_w[None, :] >= 0)
|
| 568 |
|
| 569 |
tl.store(p_final, tl.trans(b_x).to(final_state.dtype.element_ty), mask=m_final)
|
| 570 |
|
| 571 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 572 |
@input_guard(no_guard_contiguous=["x"])
|
| 573 |
def causal_conv1d_update_states(
|
| 574 |
x: torch.Tensor,
|
|
@@ -598,7 +844,7 @@ def causal_conv1d_update_states(
|
|
| 598 |
BD = min(triton.next_power_of_2(D), 256)
|
| 599 |
BW = triton.next_power_of_2(W)
|
| 600 |
|
| 601 |
-
grid = (triton.cdiv(D, BD)
|
| 602 |
|
| 603 |
causal_conv1d_states_fwd_kernel[grid](
|
| 604 |
x=x,
|
|
@@ -611,12 +857,13 @@ def causal_conv1d_update_states(
|
|
| 611 |
stride_x_n=stride_x_n,
|
| 612 |
stride_x_t=stride_x_t,
|
| 613 |
stride_x_d=stride_x_d,
|
| 614 |
-
BW=BW,
|
| 615 |
BD=BD,
|
|
|
|
| 616 |
)
|
| 617 |
return final_state
|
| 618 |
|
| 619 |
|
|
|
|
| 620 |
@input_guard(no_guard_contiguous=["x"])
|
| 621 |
def causal_conv1d_update(
|
| 622 |
x: torch.Tensor,
|
|
@@ -636,21 +883,18 @@ def causal_conv1d_update(
|
|
| 636 |
BW = triton.next_power_of_2(W)
|
| 637 |
|
| 638 |
if x.dim() == 2:
|
| 639 |
-
#
|
| 640 |
stride_x_n = x.stride(0)
|
| 641 |
stride_x_d = x.stride(1)
|
| 642 |
elif x.dim() == 3 and x.shape[0] == 1:
|
| 643 |
-
#
|
| 644 |
-
# Batch 在 dim 1
|
| 645 |
stride_x_n = x.stride(1)
|
| 646 |
stride_x_d = x.stride(2)
|
| 647 |
elif x.dim() == 3:
|
| 648 |
-
#
|
| 649 |
-
# Batch 在 dim 0
|
| 650 |
stride_x_n = x.stride(0)
|
| 651 |
stride_x_d = x.stride(2)
|
| 652 |
else:
|
| 653 |
-
# Fallback / Error case
|
| 654 |
raise ValueError(f"Unsupported input shape: {x.shape}")
|
| 655 |
|
| 656 |
y = torch.empty_like(x, memory_format=torch.contiguous_format)
|
|
@@ -662,7 +906,9 @@ def causal_conv1d_update(
|
|
| 662 |
elif y.dim() == 3:
|
| 663 |
stride_y_n, stride_y_d = y.stride(0), y.stride(2)
|
| 664 |
|
| 665 |
-
def grid(meta)
|
|
|
|
|
|
|
| 666 |
|
| 667 |
causal_conv1d_update_kernel[grid](
|
| 668 |
x=x,
|
|
@@ -681,3 +927,398 @@ def causal_conv1d_update(
|
|
| 681 |
ACTIVATION=activation,
|
| 682 |
)
|
| 683 |
return y.view(shape), cache
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 5 |
# For a list of all contributors, visit:
|
| 6 |
# https://github.com/fla-org/flash-linear-attention/graphs/contributors
|
| 7 |
|
| 8 |
+
import os
|
| 9 |
+
import warnings
|
| 10 |
+
|
| 11 |
import torch
|
| 12 |
+
import torch.nn as nn
|
| 13 |
import triton
|
| 14 |
import triton.language as tl
|
| 15 |
from einops import rearrange
|
| 16 |
|
| 17 |
+
from ...backends import dispatch
|
| 18 |
+
from ...ops.cp import FLACPContext
|
| 19 |
+
from ...ops.utils import prepare_chunk_indices
|
| 20 |
+
from ...ops.utils.cache import fla_cache_autotune
|
| 21 |
+
from ...utils import IS_AMD, autotune_cache_kwargs, deprecate_kwarg, input_guard
|
| 22 |
+
|
| 23 |
+
try:
|
| 24 |
+
from causal_conv1d import causal_conv1d_fn as causal_conv1d_fn_cuda
|
| 25 |
+
from causal_conv1d import causal_conv1d_update as causal_conv1d_update_cuda
|
| 26 |
+
except ImportError:
|
| 27 |
+
causal_conv1d_fn_cuda = None
|
| 28 |
+
causal_conv1d_update_cuda = None
|
| 29 |
|
| 30 |
NUM_WARPS_AUTOTUNE = [2, 4, 8, 16] if IS_AMD else [4, 8, 16, 32]
|
| 31 |
STATIC_WARPS = 32 if not IS_AMD else 16
|
|
|
|
| 44 |
for BD in [16, 32, 64, 128]
|
| 45 |
for num_warps in NUM_WARPS_AUTOTUNE
|
| 46 |
],
|
| 47 |
+
key=['D', 'W'],
|
| 48 |
**autotune_cache_kwargs,
|
| 49 |
)
|
| 50 |
@triton.jit
|
|
|
|
| 67 |
BT: tl.constexpr,
|
| 68 |
BW: tl.constexpr,
|
| 69 |
BD: tl.constexpr,
|
|
|
|
| 70 |
ACTIVATION: tl.constexpr,
|
| 71 |
HAS_WEIGHT: tl.constexpr,
|
| 72 |
HAS_BIAS: tl.constexpr,
|
|
|
|
| 87 |
p_x = x + tl.cast(i_b, tl.int64) * stride_x_n
|
| 88 |
|
| 89 |
o_d = i_d * BD + tl.arange(0, BD)
|
| 90 |
+
o_t = i_t.to(tl.int64) * BT + tl.arange(0, BT)
|
| 91 |
o_w = tl.arange(0, BW) + W - BW
|
| 92 |
m_d = o_d < D
|
| 93 |
m_w = o_w >= 0
|
| 94 |
+
m_y = (o_t < T)[:, None] & m_d[None, :]
|
| 95 |
|
| 96 |
if HAS_WEIGHT:
|
| 97 |
# [BD, BW]
|
|
|
|
| 100 |
b_y = tl.zeros((BT, BD), dtype=tl.float32)
|
| 101 |
if not USE_INITIAL_STATE:
|
| 102 |
for i_w in tl.static_range(-W + 1, 1):
|
| 103 |
+
o_x = o_t + i_w
|
| 104 |
+
p_yi = p_x + o_x[:, None] * stride_x_t + o_d[None, :] * stride_x_d
|
| 105 |
# [BT, BD]
|
| 106 |
+
b_yi = tl.load(p_yi, mask=((o_x >= 0) & (o_x < T))[:, None] & m_d[None, :], other=0.0).to(tl.float32)
|
| 107 |
if HAS_WEIGHT:
|
| 108 |
b_yi *= tl.sum(b_w * (o_w == (i_w + W - 1)), 1)
|
| 109 |
b_y += b_yi
|
| 110 |
elif i_t * BT >= W:
|
| 111 |
+
# separate branches avoid a Triton compiler issue.
|
| 112 |
for i_w in tl.static_range(-W + 1, 1):
|
| 113 |
+
o_x = o_t + i_w
|
| 114 |
+
p_yi = p_x + o_x[:, None] * stride_x_t + o_d[None, :] * stride_x_d
|
| 115 |
# [BT, BD]
|
| 116 |
+
b_yi = tl.load(p_yi, mask=((o_x >= 0) & (o_x < T))[:, None] & m_d[None, :], other=0.0).to(tl.float32)
|
| 117 |
if HAS_WEIGHT:
|
| 118 |
b_yi *= tl.sum(b_w * (o_w == (i_w + W - 1)), 1)
|
| 119 |
b_y += b_yi
|
| 120 |
else:
|
| 121 |
+
o_t = i_t.to(tl.int64) * BT + tl.arange(0, BT)
|
| 122 |
for i_w in tl.static_range(-W + 1, 1):
|
| 123 |
o_x = o_t + i_w
|
| 124 |
m_x = ((o_x >= 0) & (o_x < T))[:, None] & m_d
|
| 125 |
m_c = ((o_x + W >= 0) & (o_x < 0))[:, None] & m_d
|
| 126 |
|
| 127 |
+
b_yi = tl.load(p_x + o_x[:, None] * stride_x_t + o_d * stride_x_d, mask=m_x, other=0).to(tl.float32)
|
|
|
|
|
|
|
|
|
|
|
|
|
| 128 |
|
| 129 |
b_yi += tl.load(initial_state + i_n * D*W + o_d * W + (o_x + W)[:, None], mask=m_c, other=0).to(tl.float32)
|
| 130 |
|
|
|
|
| 139 |
b_y = b_y * tl.sigmoid(b_y)
|
| 140 |
|
| 141 |
if HAS_RESIDUAL:
|
| 142 |
+
p_residual = residual + bos * D + o_t[:, None] * D + o_d[None, :]
|
| 143 |
+
b_residual = tl.load(p_residual, mask=m_y, other=0.0)
|
| 144 |
b_y += b_residual
|
| 145 |
|
| 146 |
+
p_y = y + bos * D + o_t[:, None] * D + o_d[None, :]
|
| 147 |
+
tl.store(p_y, tl.cast(b_y, dtype=p_y.dtype.element_ty, fp_downcast_rounding='rtne'), mask=m_y)
|
| 148 |
|
| 149 |
|
| 150 |
@triton.heuristics({
|
|
|
|
| 158 |
configs=[
|
| 159 |
triton.Config({'BD': BD}, num_warps=num_warps)
|
| 160 |
for BD in [16, 32, 64, 128]
|
| 161 |
+
for num_warps in NUM_WARPS_AUTOTUNE
|
| 162 |
],
|
| 163 |
+
key=['D', 'W'],
|
| 164 |
**autotune_cache_kwargs,
|
| 165 |
)
|
| 166 |
@triton.jit
|
|
|
|
| 178 |
chunk_indices,
|
| 179 |
B,
|
| 180 |
T,
|
| 181 |
+
stride_x_n,
|
| 182 |
+
stride_x_t,
|
| 183 |
+
stride_x_d,
|
| 184 |
+
stride_dx_n,
|
| 185 |
+
stride_dx_t,
|
| 186 |
+
stride_dx_d,
|
| 187 |
+
stride_dy_n,
|
| 188 |
+
stride_dy_t,
|
| 189 |
+
stride_dy_d,
|
| 190 |
D: tl.constexpr,
|
| 191 |
W: tl.constexpr,
|
| 192 |
BT: tl.constexpr,
|
| 193 |
BW: tl.constexpr,
|
| 194 |
BD: tl.constexpr,
|
|
|
|
| 195 |
ACTIVATION: tl.constexpr,
|
| 196 |
HAS_WEIGHT: tl.constexpr,
|
| 197 |
HAS_BIAS: tl.constexpr,
|
|
|
|
| 218 |
p_dy = dy + tl.cast(i_b, tl.int64) * stride_dy_n
|
| 219 |
|
| 220 |
o_d = i_d * BD + tl.arange(0, BD)
|
| 221 |
+
o_t = i_t.to(tl.int64) * BT + tl.arange(0, BT)
|
| 222 |
o_w = tl.arange(0, BW) + W - BW
|
| 223 |
m_d = o_d < D
|
| 224 |
m_w = o_w >= 0
|
| 225 |
+
m_x = (o_t < T)[:, None] & m_d[None, :]
|
| 226 |
|
| 227 |
if HAS_WEIGHT:
|
| 228 |
+
p_x = p_x + o_t[:, None] * stride_x_t + o_d[None, :] * stride_x_d
|
| 229 |
+
b_x = tl.load(p_x, mask=m_x, other=0.0)
|
| 230 |
# [BD, BW]
|
| 231 |
b_w = tl.load(weight + o_d[:, None] * W + o_w, mask=m_d[:, None] & m_w, other=0)
|
| 232 |
|
|
|
|
| 236 |
|
| 237 |
if not USE_FINAL_STATE and not USE_INITIAL_STATE:
|
| 238 |
for i_w in tl.static_range(0, W):
|
| 239 |
+
o_dy = o_t + i_w
|
| 240 |
+
p_dy_blk = p_dy + o_dy[:, None] * stride_dy_t + o_d[None, :] * stride_dy_d
|
| 241 |
# [BT, BD]
|
| 242 |
+
b_dy = tl.load(p_dy_blk, mask=((o_dy < T)[:, None] & m_d[None, :]), other=0.0).to(tl.float32)
|
| 243 |
if ACTIVATION == 'swish' or ACTIVATION == 'silu':
|
| 244 |
+
p_y = y + bos * D + o_dy[:, None] * D + o_d[None, :]
|
| 245 |
+
b_y = tl.load(p_y, mask=((o_dy < T)[:, None] & m_d[None, :]), other=0.0).to(tl.float32)
|
| 246 |
b_ys = tl.sigmoid(b_y)
|
| 247 |
b_dy = b_dy * b_ys * (1 + b_y * (1 - b_ys))
|
| 248 |
b_wdy = b_dy
|
|
|
|
| 256 |
b_db += tl.sum(b_dy, 0)
|
| 257 |
b_dx += b_wdy
|
| 258 |
elif i_t * BT >= W:
|
| 259 |
+
# separate branches avoid a Triton compiler issue.
|
| 260 |
for i_w in tl.static_range(0, W):
|
| 261 |
+
o_dy = o_t + i_w
|
| 262 |
+
p_dy_blk = p_dy + o_dy[:, None] * stride_dy_t + o_d[None, :] * stride_dy_d
|
| 263 |
# [BT, BD]
|
| 264 |
+
b_dy = tl.load(p_dy_blk, mask=((o_dy < T)[:, None] & m_d[None, :]), other=0.0).to(tl.float32)
|
| 265 |
if ACTIVATION == 'swish' or ACTIVATION == 'silu':
|
| 266 |
+
p_y = y + bos * D + o_dy[:, None] * D + o_d[None, :]
|
| 267 |
+
b_y = tl.load(p_y, mask=((o_dy < T)[:, None] & m_d[None, :]), other=0.0).to(tl.float32)
|
| 268 |
b_ys = tl.sigmoid(b_y)
|
| 269 |
b_dy = b_dy * b_ys * (1 + b_y * (1 - b_ys))
|
| 270 |
b_wdy = b_dy
|
|
|
|
| 278 |
b_db += tl.sum(b_dy, 0)
|
| 279 |
b_dx += b_wdy
|
| 280 |
else:
|
| 281 |
+
o_t = i_t.to(tl.int64) * BT + tl.arange(0, BT)
|
|
|
|
| 282 |
for i_w in tl.static_range(0, W):
|
| 283 |
+
o_dy = o_t + i_w
|
| 284 |
+
p_dy_blk = p_dy + o_dy[:, None] * stride_dy_t + o_d[None, :] * stride_dy_d
|
| 285 |
+
b_dy_shift = tl.load(p_dy_blk, mask=((o_dy < T)[:, None] & m_d[None, :]), other=0.0).to(tl.float32)
|
| 286 |
if ACTIVATION == 'swish' or ACTIVATION == 'silu':
|
| 287 |
+
p_y = y + bos * D + o_dy[:, None] * D + o_d[None, :]
|
| 288 |
+
b_y_shift = tl.load(p_y, mask=((o_dy < T)[:, None] & m_d[None, :]), other=0.0).to(tl.float32)
|
| 289 |
b_ys = tl.sigmoid(b_y_shift)
|
| 290 |
b_dy_shift = b_dy_shift * b_ys * (1 + b_y_shift * (1 - b_ys))
|
| 291 |
if HAS_WEIGHT:
|
|
|
|
| 292 |
b_dw = tl.sum(b_dy_shift * b_x, 0)
|
|
|
|
| 293 |
if USE_INITIAL_STATE:
|
| 294 |
mask_head_rows = (o_t < i_w) & (o_t < T)
|
| 295 |
+
b_dy_head = tl.load(
|
| 296 |
+
p_dy + o_t[:, None] * stride_dy_t + o_d * stride_dy_d,
|
| 297 |
+
mask=mask_head_rows[:, None] & m_d[None, :],
|
| 298 |
+
other=0.0,
|
| 299 |
+
).to(tl.float32)
|
| 300 |
if ACTIVATION == 'swish' or ACTIVATION == 'silu':
|
| 301 |
+
# cache gradients use the unshifted preactivation y[t].
|
| 302 |
+
b_y_head = tl.load(
|
| 303 |
+
y + bos * D + o_t[:, None] * D + o_d,
|
| 304 |
+
mask=mask_head_rows[:, None] & m_d[None, :],
|
| 305 |
+
other=0.0,
|
| 306 |
+
).to(tl.float32)
|
| 307 |
b_ys_head = tl.sigmoid(b_y_head)
|
| 308 |
b_dy_head = b_dy_head * b_ys_head * (1 + b_y_head * (1 - b_ys_head))
|
| 309 |
o_c = W - i_w + o_t
|
| 310 |
# index 0 is padding 0
|
| 311 |
mask_c = (mask_head_rows & (o_c >= 1) & (o_c < W))
|
| 312 |
+
b_xc = tl.load(
|
| 313 |
+
initial_state + i_n * D * W + o_d[None, :] * W + o_c[:, None],
|
| 314 |
+
mask=mask_c[:, None] & m_d[None, :],
|
| 315 |
+
other=0.0,
|
| 316 |
+
).to(tl.float32)
|
| 317 |
b_dw += tl.sum(b_dy_head * b_xc, 0)
|
| 318 |
tl.store(dw + i_tg * D * W + o_d * W + W - i_w - 1, b_dw.to(dw.dtype.element_ty), mask=m_d)
|
| 319 |
|
|
|
|
| 330 |
if i_t * BT + BT >= T-W:
|
| 331 |
start_tok = max(0, T - (W - 1))
|
| 332 |
offset = i_t * BT + tl.arange(0, BT)
|
|
|
|
| 333 |
mask = (offset >= start_tok) & (offset < T)
|
| 334 |
+
# state slot w is token T - W + w, so token t takes dht[:, t + W - T].
|
| 335 |
+
# start_tok is clamped, which only matters for the mask (offset >= 0 anyway),
|
| 336 |
+
# so the slot index has to come from the unclamped expression.
|
| 337 |
+
w_idx = offset + (W - T)
|
| 338 |
dht_off = i_n * D * W + o_d[None, :] * W + w_idx[:, None]
|
| 339 |
b_dht = tl.load(dht + dht_off, mask=mask[:, None] & m_d[None, :], other=0.).to(tl.float32)
|
| 340 |
b_dx += b_dht
|
|
|
|
| 344 |
else:
|
| 345 |
p_dx = dx + tl.cast(i_b, tl.int64) * stride_dx_n
|
| 346 |
|
| 347 |
+
p_dx = p_dx + o_t[:, None] * stride_dx_t + o_d[None, :] * stride_dx_d
|
| 348 |
+
tl.store(p_dx, tl.cast(b_dx, dtype=p_dx.dtype.element_ty, fp_downcast_rounding='rtne'), mask=m_x)
|
| 349 |
|
| 350 |
|
| 351 |
@triton.heuristics({
|
|
|
|
| 372 |
y,
|
| 373 |
weight,
|
| 374 |
bias,
|
| 375 |
+
stride_x_n,
|
| 376 |
+
stride_x_d,
|
| 377 |
+
stride_y_n,
|
| 378 |
+
stride_y_d,
|
| 379 |
D: tl.constexpr,
|
| 380 |
W: tl.constexpr,
|
| 381 |
BD: tl.constexpr,
|
|
|
|
| 386 |
HAS_BIAS: tl.constexpr,
|
| 387 |
HAS_RESIDUAL: tl.constexpr,
|
| 388 |
):
|
| 389 |
+
pid = tl.program_id(0)
|
| 390 |
+
ND = tl.cdiv(D, BD)
|
| 391 |
+
i_d, i_n = pid % ND, (pid // ND).to(tl.int64)
|
| 392 |
|
| 393 |
o_d = i_d * BD + tl.arange(0, BD)
|
| 394 |
o_w = tl.arange(0, BW)
|
|
|
|
| 401 |
b_cache = tl.zeros((BD, BW), dtype=tl.float32)
|
| 402 |
|
| 403 |
if USE_INITIAL_STATE:
|
| 404 |
+
p_cache_read = cache + i_n * D*W + o_d[:, None] * W + (o_w + 1)[None, :]
|
| 405 |
+
b_cache = tl.load(p_cache_read, mask=m_d[:, None] & ((o_w + 1) < W)[None, :], other=0.0).to(tl.float32)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 406 |
|
|
|
|
| 407 |
m_update = o_w == (W - 1)
|
| 408 |
b_cache = tl.where(m_update[None, :], b_x[:, None], b_cache)
|
| 409 |
|
|
|
|
| 422 |
if HAS_RESIDUAL:
|
| 423 |
b_y += tl.load(residual + i_n * D + o_d, mask=m_d, other=0)
|
| 424 |
|
| 425 |
+
tl.store(
|
| 426 |
+
y + i_n * stride_y_n + o_d * stride_y_d,
|
| 427 |
+
tl.cast(b_y, dtype=y.dtype.element_ty, fp_downcast_rounding='rtne'),
|
| 428 |
+
mask=m_d,
|
| 429 |
+
)
|
| 430 |
|
| 431 |
if USE_INITIAL_STATE:
|
| 432 |
+
p_cache_write = cache + i_n * D*W + o_d[:, None] * W + o_w[None, :]
|
| 433 |
+
tl.store(
|
| 434 |
+
p_cache_write,
|
| 435 |
+
tl.cast(b_cache, dtype=cache.dtype.element_ty, fp_downcast_rounding='rtne'),
|
| 436 |
+
mask=m_d[:, None] & m_w[None, :],
|
|
|
|
|
|
|
| 437 |
)
|
|
|
|
|
|
|
| 438 |
|
| 439 |
|
| 440 |
@triton.heuristics({
|
| 441 |
'USE_ACTIVATION': lambda args: args['y'] is not None,
|
| 442 |
+
'USE_FINAL_STATE': lambda args: args['dht'] is not None,
|
| 443 |
'IS_VARLEN': lambda args: args['cu_seqlens'] is not None,
|
| 444 |
})
|
| 445 |
@triton.jit
|
|
|
|
| 448 |
y,
|
| 449 |
weight,
|
| 450 |
dh0,
|
| 451 |
+
dht,
|
| 452 |
cu_seqlens,
|
| 453 |
stride_dy_n,
|
| 454 |
stride_dy_t,
|
| 455 |
+
stride_dy_d,
|
| 456 |
T,
|
| 457 |
D: tl.constexpr,
|
| 458 |
W: tl.constexpr,
|
| 459 |
BD: tl.constexpr,
|
| 460 |
USE_ACTIVATION: tl.constexpr,
|
| 461 |
+
USE_FINAL_STATE: tl.constexpr,
|
| 462 |
IS_VARLEN: tl.constexpr,
|
| 463 |
):
|
| 464 |
"""
|
| 465 |
Compute dh0 (gradient w.r.t. initial_state) in a separate kernel.
|
| 466 |
This avoids Triton compiler bugs on some architectures (e.g., GB200).
|
| 467 |
|
| 468 |
+
Grid: (cdiv(D, BD) * N,)
|
| 469 |
"""
|
| 470 |
+
pid = tl.program_id(0)
|
| 471 |
+
ND = tl.cdiv(D, BD)
|
| 472 |
+
i_d, i_n = pid % ND, (pid // ND).to(tl.int64)
|
| 473 |
|
|
|
|
| 474 |
if IS_VARLEN:
|
| 475 |
bos = tl.load(cu_seqlens + i_n).to(tl.int64)
|
| 476 |
eos = tl.load(cu_seqlens + i_n + 1).to(tl.int64)
|
| 477 |
seq_len = eos - bos
|
| 478 |
+
# for varlen, dy is [1, total_T, D], offset by bos
|
| 479 |
dy_base = dy + bos * stride_dy_t
|
| 480 |
else:
|
| 481 |
seq_len = T
|
| 482 |
+
# for non-varlen, dy is [B, T, D], offset by i_n * stride_dy_n
|
| 483 |
dy_base = dy + tl.cast(i_n, tl.int64) * stride_dy_n
|
| 484 |
|
| 485 |
o_d = i_d * BD + tl.arange(0, BD)
|
| 486 |
m_d = o_d < D
|
| 487 |
|
|
|
|
| 488 |
for i_w in tl.static_range(1, W):
|
| 489 |
b_dh0 = tl.zeros([BD], dtype=tl.float32)
|
| 490 |
|
| 491 |
+
if USE_FINAL_STATE:
|
| 492 |
+
# short sequences retain initial_state[:, i_w] in final_state[:, i_w - seq_len],
|
| 493 |
+
# so that slot's gradient passes straight through.
|
| 494 |
+
if i_w >= seq_len:
|
| 495 |
+
p_dht = dht + i_n * D * W + o_d * W + (i_w - seq_len)
|
| 496 |
+
b_dh0 += tl.load(p_dht, mask=m_d, other=0).to(tl.float32)
|
| 497 |
+
|
| 498 |
for t in tl.static_range(0, W - 1):
|
| 499 |
if t < i_w:
|
| 500 |
w_idx = i_w - 1 - t
|
| 501 |
|
| 502 |
+
p_dy = dy_base + t * stride_dy_t + o_d * stride_dy_d
|
|
|
|
| 503 |
m_t = (t < seq_len) & m_d
|
| 504 |
b_dy = tl.load(p_dy, mask=m_t, other=0).to(tl.float32)
|
| 505 |
|
| 506 |
if USE_ACTIVATION:
|
| 507 |
+
# `y` is recomputed contiguous [*, T, D]; only `dy` may carry other strides
|
| 508 |
if IS_VARLEN:
|
| 509 |
+
p_y = y + bos * D + t * D + o_d
|
| 510 |
else:
|
| 511 |
+
p_y = y + tl.cast(i_n, tl.int64) * T * D + t * D + o_d
|
| 512 |
b_y = tl.load(p_y, mask=m_t, other=0).to(tl.float32)
|
| 513 |
b_ys = tl.sigmoid(b_y)
|
| 514 |
b_dy = b_dy * b_ys * (1 + b_y * (1 - b_ys))
|
| 515 |
|
|
|
|
| 516 |
b_w_col = tl.load(weight + o_d * W + w_idx, mask=m_d, other=0).to(tl.float32)
|
| 517 |
|
|
|
|
| 518 |
b_dh0 += tl.where(m_t, b_dy * b_w_col, 0)
|
| 519 |
|
|
|
|
| 520 |
p_dh0 = dh0 + i_n * D * W + o_d * W + i_w
|
| 521 |
tl.store(p_dh0, b_dh0.to(dh0.dtype.element_ty), mask=m_d)
|
| 522 |
|
|
|
|
| 542 |
USE_INITIAL_STATE: tl.constexpr,
|
| 543 |
IS_VARLEN: tl.constexpr,
|
| 544 |
):
|
| 545 |
+
pid = tl.program_id(0)
|
| 546 |
+
ND = tl.cdiv(D, BD)
|
| 547 |
+
i_d, i_n = pid % ND, (pid // ND).to(tl.int64)
|
| 548 |
|
| 549 |
+
# [BD]
|
| 550 |
o_d = i_d * BD + tl.arange(0, BD)
|
| 551 |
m_d = o_d < D
|
| 552 |
|
|
|
|
| 559 |
seq_len = T
|
| 560 |
p_x = x + tl.cast(i_n, tl.int64) * stride_x_n
|
| 561 |
|
| 562 |
+
o_x = tl.cast(seq_len, tl.int64) - BW + tl.arange(0, BW)
|
| 563 |
+
p_x = p_x + o_x[:, None] * stride_x_t + o_d[None, :] * stride_x_d
|
| 564 |
|
| 565 |
+
# [BW, BD]
|
| 566 |
+
b_x = tl.load(p_x, mask=((o_x >= 0) & (o_x < seq_len))[:, None] & m_d[None, :], other=0.0).to(tl.float32)
|
| 567 |
|
| 568 |
if USE_INITIAL_STATE:
|
| 569 |
if seq_len < BW:
|
|
|
|
| 576 |
b_cache = tl.load(p_init, mask=mask_init, other=0)
|
| 577 |
b_x += b_cache
|
| 578 |
|
| 579 |
+
# final_state: [N, D, W]
|
| 580 |
+
# [BW]
|
| 581 |
o_w = W - BW + tl.arange(0, BW)
|
| 582 |
|
| 583 |
# o_d[:, None] -> [BD, 1]
|
| 584 |
# o_w[None, :] -> [1, BW]
|
| 585 |
+
# [BD, BW]
|
| 586 |
p_final = final_state + tl.cast(i_n, tl.int64) * D*W + o_d[:, None] * W + o_w[None, :]
|
| 587 |
|
| 588 |
+
# [BD, BW]
|
| 589 |
m_final = m_d[:, None] & (o_w[None, :] >= 0)
|
| 590 |
|
| 591 |
tl.store(p_final, tl.trans(b_x).to(final_state.dtype.element_ty), mask=m_final)
|
| 592 |
|
| 593 |
|
| 594 |
+
def _has_non_standard_layout(x: torch.Tensor) -> bool:
|
| 595 |
+
"""QKV-style views (stride_t != D) break triton-ascend masked kernels."""
|
| 596 |
+
if x.dtype not in (torch.float16, torch.bfloat16):
|
| 597 |
+
return False
|
| 598 |
+
if x.dim() != 3:
|
| 599 |
+
return not x.is_contiguous()
|
| 600 |
+
_, stride_t, stride_d = x.stride()
|
| 601 |
+
return stride_d == 1 and stride_t != x.shape[-1]
|
| 602 |
+
|
| 603 |
+
|
| 604 |
+
@deprecate_kwarg('BT', version='0.7.0', new_name='chunk_size')
|
| 605 |
+
@dispatch
|
| 606 |
+
@input_guard(no_guard_contiguous=["x"])
|
| 607 |
+
def causal_conv1d_fwd(
|
| 608 |
+
x: torch.Tensor,
|
| 609 |
+
weight: torch.Tensor,
|
| 610 |
+
bias: torch.Tensor,
|
| 611 |
+
residual: torch.Tensor,
|
| 612 |
+
initial_state: torch.Tensor | None = None,
|
| 613 |
+
output_final_state: bool = False,
|
| 614 |
+
activation: str | None = None,
|
| 615 |
+
cu_seqlens: torch.LongTensor | None = None,
|
| 616 |
+
cu_seqlens_cpu: torch.LongTensor | None = None,
|
| 617 |
+
chunk_indices: torch.LongTensor | None = None,
|
| 618 |
+
chunk_size: int = 64,
|
| 619 |
+
layout_fallback: bool = False,
|
| 620 |
+
) -> torch.Tensor:
|
| 621 |
+
BT = chunk_size
|
| 622 |
+
shape = x.shape
|
| 623 |
+
if x.shape[-1] != weight.shape[0]:
|
| 624 |
+
x = rearrange(x, 'b t ... -> b t (...)')
|
| 625 |
+
B, T, D = x.shape[0], x.shape[1], weight.shape[0]
|
| 626 |
+
W = weight.shape[1]
|
| 627 |
+
stride_x_n, stride_x_t, stride_x_d = x.stride()
|
| 628 |
+
|
| 629 |
+
BW = triton.next_power_of_2(W)
|
| 630 |
+
if cu_seqlens is not None and chunk_indices is None:
|
| 631 |
+
chunk_indices = prepare_chunk_indices(cu_seqlens, BT, cu_seqlens_cpu=cu_seqlens_cpu)
|
| 632 |
+
NT = len(chunk_indices) if cu_seqlens is not None else triton.cdiv(T, BT)
|
| 633 |
+
|
| 634 |
+
y = torch.empty_like(x, memory_format=torch.contiguous_format)
|
| 635 |
+
|
| 636 |
+
def grid(meta) -> tuple[int, ...]:
|
| 637 |
+
|
| 638 |
+
return (triton.cdiv(D, meta['BD']), NT, B)
|
| 639 |
+
causal_conv1d_fwd_kernel[grid](
|
| 640 |
+
x=x,
|
| 641 |
+
y=y,
|
| 642 |
+
weight=weight,
|
| 643 |
+
bias=bias,
|
| 644 |
+
residual=residual,
|
| 645 |
+
cu_seqlens=cu_seqlens,
|
| 646 |
+
initial_state=initial_state,
|
| 647 |
+
chunk_indices=chunk_indices,
|
| 648 |
+
B=B,
|
| 649 |
+
T=T,
|
| 650 |
+
stride_x_n=stride_x_n,
|
| 651 |
+
stride_x_t=stride_x_t,
|
| 652 |
+
stride_x_d=stride_x_d,
|
| 653 |
+
D=D,
|
| 654 |
+
W=W,
|
| 655 |
+
BT=BT,
|
| 656 |
+
BW=BW,
|
| 657 |
+
ACTIVATION=activation,
|
| 658 |
+
)
|
| 659 |
+
final_state = None
|
| 660 |
+
if output_final_state:
|
| 661 |
+
final_state = causal_conv1d_update_states(x=x, state_len=W, initial_state=initial_state, cu_seqlens=cu_seqlens)
|
| 662 |
+
return y.view(shape), final_state
|
| 663 |
+
|
| 664 |
+
|
| 665 |
+
@dispatch
|
| 666 |
+
def compute_dh0_triton(
|
| 667 |
+
dy: torch.Tensor,
|
| 668 |
+
y: torch.Tensor | None,
|
| 669 |
+
weight: torch.Tensor,
|
| 670 |
+
initial_state: torch.Tensor,
|
| 671 |
+
activation: str | None,
|
| 672 |
+
cu_seqlens: torch.Tensor | None,
|
| 673 |
+
dht: torch.Tensor | None = None,
|
| 674 |
+
) -> torch.Tensor:
|
| 675 |
+
"""
|
| 676 |
+
Compute dh0 (gradient w.r.t. initial_state) using a separate Triton kernel.
|
| 677 |
+
This is a workaround for Triton compiler bugs on some architectures (e.g., GB200).
|
| 678 |
+
"""
|
| 679 |
+
D, W = weight.shape
|
| 680 |
+
N = initial_state.shape[0]
|
| 681 |
+
T = dy.shape[1]
|
| 682 |
+
|
| 683 |
+
dh0 = torch.zeros_like(initial_state)
|
| 684 |
+
|
| 685 |
+
BD = 32
|
| 686 |
+
grid = (triton.cdiv(D, BD) * N,)
|
| 687 |
+
|
| 688 |
+
y_to_pass = y if activation in ('swish', 'silu') else None
|
| 689 |
+
# dy is [B, T, D] but may be a strided view; `y` is always contiguous
|
| 690 |
+
stride_dy_n, stride_dy_t, stride_dy_d = dy.stride()
|
| 691 |
+
|
| 692 |
+
compute_dh0_kernel[grid](
|
| 693 |
+
dy=dy,
|
| 694 |
+
y=y_to_pass,
|
| 695 |
+
weight=weight,
|
| 696 |
+
dh0=dh0,
|
| 697 |
+
dht=dht,
|
| 698 |
+
cu_seqlens=cu_seqlens,
|
| 699 |
+
stride_dy_n=stride_dy_n,
|
| 700 |
+
stride_dy_t=stride_dy_t,
|
| 701 |
+
stride_dy_d=stride_dy_d,
|
| 702 |
+
T=T,
|
| 703 |
+
D=D,
|
| 704 |
+
W=W,
|
| 705 |
+
BD=BD,
|
| 706 |
+
)
|
| 707 |
+
|
| 708 |
+
return dh0
|
| 709 |
+
|
| 710 |
+
|
| 711 |
+
@deprecate_kwarg('BT', version='0.7.0', new_name='chunk_size')
|
| 712 |
+
@dispatch
|
| 713 |
+
def causal_conv1d_bwd(
|
| 714 |
+
x: torch.Tensor,
|
| 715 |
+
dy: torch.Tensor,
|
| 716 |
+
dht: torch.Tensor,
|
| 717 |
+
weight: torch.Tensor | None = None,
|
| 718 |
+
bias: torch.Tensor | None = None,
|
| 719 |
+
residual: torch.Tensor | None = None,
|
| 720 |
+
initial_state: torch.Tensor | None = None,
|
| 721 |
+
activation: str | None = None,
|
| 722 |
+
cu_seqlens: torch.Tensor | None = None,
|
| 723 |
+
cu_seqlens_cpu: torch.LongTensor | None = None,
|
| 724 |
+
chunk_indices: torch.LongTensor | None = None,
|
| 725 |
+
chunk_size: int = 64,
|
| 726 |
+
layout_fallback: bool = False,
|
| 727 |
+
) -> tuple[torch.Tensor, torch.Tensor | None, torch.Tensor | None, torch.Tensor | None, torch.Tensor | None]:
|
| 728 |
+
BT = chunk_size
|
| 729 |
+
shape = x.shape
|
| 730 |
+
if x.shape[-1] != weight.shape[0]:
|
| 731 |
+
x = rearrange(x, 'b t ... -> b t (...)')
|
| 732 |
+
B, T, D = x.shape
|
| 733 |
+
W = weight.shape[1] if weight is not None else None
|
| 734 |
+
|
| 735 |
+
stride_x_n, stride_x_t, stride_x_d = x.stride()
|
| 736 |
+
stride_dy_n, stride_dy_t, stride_dy_d = dy.stride()
|
| 737 |
+
|
| 738 |
+
BW = triton.next_power_of_2(W)
|
| 739 |
+
if cu_seqlens is not None and chunk_indices is None:
|
| 740 |
+
chunk_indices = prepare_chunk_indices(cu_seqlens, BT, cu_seqlens_cpu=cu_seqlens_cpu)
|
| 741 |
+
NT = len(chunk_indices) if cu_seqlens is not None else triton.cdiv(T, BT)
|
| 742 |
+
|
| 743 |
+
y = None
|
| 744 |
+
if activation is not None:
|
| 745 |
+
y, _ = causal_conv1d_fwd(
|
| 746 |
+
x=x,
|
| 747 |
+
weight=weight,
|
| 748 |
+
bias=bias,
|
| 749 |
+
residual=None,
|
| 750 |
+
initial_state=initial_state,
|
| 751 |
+
output_final_state=False,
|
| 752 |
+
activation=None,
|
| 753 |
+
cu_seqlens=cu_seqlens,
|
| 754 |
+
cu_seqlens_cpu=cu_seqlens_cpu,
|
| 755 |
+
chunk_indices=chunk_indices,
|
| 756 |
+
)
|
| 757 |
+
dx = torch.empty_like(x)
|
| 758 |
+
dw = weight.new_empty(B*NT, *weight.shape, dtype=torch.float) if weight is not None else None
|
| 759 |
+
db = bias.new_empty(B*NT, *bias.shape, dtype=torch.float) if bias is not None else None
|
| 760 |
+
dr = dy if residual is not None else None
|
| 761 |
+
|
| 762 |
+
stride_dx_n, stride_dx_t, stride_dx_d = dx.stride()
|
| 763 |
+
|
| 764 |
+
def grid(meta) -> tuple[int, ...]:
|
| 765 |
+
|
| 766 |
+
return (triton.cdiv(D, meta['BD']), NT, B)
|
| 767 |
+
causal_conv1d_bwd_kernel[grid](
|
| 768 |
+
x=x,
|
| 769 |
+
y=y,
|
| 770 |
+
weight=weight,
|
| 771 |
+
initial_state=initial_state,
|
| 772 |
+
dht=dht,
|
| 773 |
+
dy=dy,
|
| 774 |
+
dx=dx,
|
| 775 |
+
dw=dw,
|
| 776 |
+
db=db,
|
| 777 |
+
cu_seqlens=cu_seqlens,
|
| 778 |
+
chunk_indices=chunk_indices,
|
| 779 |
+
B=B,
|
| 780 |
+
T=T,
|
| 781 |
+
stride_x_n=stride_x_n,
|
| 782 |
+
stride_x_t=stride_x_t,
|
| 783 |
+
stride_x_d=stride_x_d,
|
| 784 |
+
stride_dx_n=stride_dx_n,
|
| 785 |
+
stride_dx_t=stride_dx_t,
|
| 786 |
+
stride_dx_d=stride_dx_d,
|
| 787 |
+
stride_dy_n=stride_dy_n,
|
| 788 |
+
stride_dy_t=stride_dy_t,
|
| 789 |
+
stride_dy_d=stride_dy_d,
|
| 790 |
+
D=D,
|
| 791 |
+
W=W,
|
| 792 |
+
BT=BT,
|
| 793 |
+
BW=BW,
|
| 794 |
+
ACTIVATION=activation,
|
| 795 |
+
)
|
| 796 |
+
if weight is not None:
|
| 797 |
+
dw = dw.sum(0).to(weight)
|
| 798 |
+
if bias is not None:
|
| 799 |
+
db = db.sum(0).to(bias)
|
| 800 |
+
|
| 801 |
+
# compute dh0 using separate Triton kernel to avoid compiler bugs on some architectures (e.g., GB200)
|
| 802 |
+
dh0 = None
|
| 803 |
+
if initial_state is not None:
|
| 804 |
+
dh0 = compute_dh0_triton(
|
| 805 |
+
dy=dy,
|
| 806 |
+
y=y,
|
| 807 |
+
weight=weight,
|
| 808 |
+
initial_state=initial_state,
|
| 809 |
+
activation=activation,
|
| 810 |
+
cu_seqlens=cu_seqlens,
|
| 811 |
+
dht=dht,
|
| 812 |
+
)
|
| 813 |
+
|
| 814 |
+
return dx.view(shape), dw, db, dr, dh0
|
| 815 |
+
|
| 816 |
+
|
| 817 |
+
@dispatch
|
| 818 |
@input_guard(no_guard_contiguous=["x"])
|
| 819 |
def causal_conv1d_update_states(
|
| 820 |
x: torch.Tensor,
|
|
|
|
| 844 |
BD = min(triton.next_power_of_2(D), 256)
|
| 845 |
BW = triton.next_power_of_2(W)
|
| 846 |
|
| 847 |
+
grid = (triton.cdiv(D, BD) * N,)
|
| 848 |
|
| 849 |
causal_conv1d_states_fwd_kernel[grid](
|
| 850 |
x=x,
|
|
|
|
| 857 |
stride_x_n=stride_x_n,
|
| 858 |
stride_x_t=stride_x_t,
|
| 859 |
stride_x_d=stride_x_d,
|
|
|
|
| 860 |
BD=BD,
|
| 861 |
+
BW=BW,
|
| 862 |
)
|
| 863 |
return final_state
|
| 864 |
|
| 865 |
|
| 866 |
+
@dispatch
|
| 867 |
@input_guard(no_guard_contiguous=["x"])
|
| 868 |
def causal_conv1d_update(
|
| 869 |
x: torch.Tensor,
|
|
|
|
| 883 |
BW = triton.next_power_of_2(W)
|
| 884 |
|
| 885 |
if x.dim() == 2:
|
| 886 |
+
# case: (N, D)
|
| 887 |
stride_x_n = x.stride(0)
|
| 888 |
stride_x_d = x.stride(1)
|
| 889 |
elif x.dim() == 3 and x.shape[0] == 1:
|
| 890 |
+
# [1, N, D]: one token per sequence
|
|
|
|
| 891 |
stride_x_n = x.stride(1)
|
| 892 |
stride_x_d = x.stride(2)
|
| 893 |
elif x.dim() == 3:
|
| 894 |
+
# [N, 1, D]: one token per sequence
|
|
|
|
| 895 |
stride_x_n = x.stride(0)
|
| 896 |
stride_x_d = x.stride(2)
|
| 897 |
else:
|
|
|
|
| 898 |
raise ValueError(f"Unsupported input shape: {x.shape}")
|
| 899 |
|
| 900 |
y = torch.empty_like(x, memory_format=torch.contiguous_format)
|
|
|
|
| 906 |
elif y.dim() == 3:
|
| 907 |
stride_y_n, stride_y_d = y.stride(0), y.stride(2)
|
| 908 |
|
| 909 |
+
def grid(meta) -> tuple[int, ...]:
|
| 910 |
+
|
| 911 |
+
return (triton.cdiv(D, meta['BD']) * N,)
|
| 912 |
|
| 913 |
causal_conv1d_update_kernel[grid](
|
| 914 |
x=x,
|
|
|
|
| 927 |
ACTIVATION=activation,
|
| 928 |
)
|
| 929 |
return y.view(shape), cache
|
| 930 |
+
|
| 931 |
+
|
| 932 |
+
class CausalConv1dFunction(torch.autograd.Function):
|
| 933 |
+
|
| 934 |
+
@staticmethod
|
| 935 |
+
@input_guard(no_guard_contiguous=["x"])
|
| 936 |
+
def forward(
|
| 937 |
+
ctx,
|
| 938 |
+
x: torch.Tensor,
|
| 939 |
+
weight: torch.Tensor | None = None,
|
| 940 |
+
bias: torch.Tensor | None = None,
|
| 941 |
+
residual: torch.Tensor | None = None,
|
| 942 |
+
initial_state: torch.Tensor | None = None,
|
| 943 |
+
output_final_state: bool | None = False,
|
| 944 |
+
activation: str | None = None,
|
| 945 |
+
cu_seqlens: torch.Tensor | None = None,
|
| 946 |
+
cu_seqlens_cpu: torch.LongTensor | None = None,
|
| 947 |
+
chunk_indices: torch.LongTensor | None = None,
|
| 948 |
+
chunk_size: int = 64,
|
| 949 |
+
) -> tuple[torch.Tensor, torch.Tensor | None]:
|
| 950 |
+
if cu_seqlens is not None and chunk_indices is None:
|
| 951 |
+
chunk_indices = prepare_chunk_indices(cu_seqlens, chunk_size, cu_seqlens_cpu=cu_seqlens_cpu)
|
| 952 |
+
ctx.activation = activation
|
| 953 |
+
ctx.cu_seqlens = cu_seqlens
|
| 954 |
+
ctx.cu_seqlens_cpu = cu_seqlens_cpu
|
| 955 |
+
ctx.chunk_indices = chunk_indices
|
| 956 |
+
ctx.layout_fallback = _has_non_standard_layout(x=x)
|
| 957 |
+
ctx.save_for_backward(x, weight, bias, residual, initial_state)
|
| 958 |
+
y, final_state = causal_conv1d_fwd(
|
| 959 |
+
x=x,
|
| 960 |
+
weight=weight,
|
| 961 |
+
bias=bias,
|
| 962 |
+
residual=residual,
|
| 963 |
+
initial_state=initial_state,
|
| 964 |
+
output_final_state=output_final_state,
|
| 965 |
+
activation=activation,
|
| 966 |
+
cu_seqlens=cu_seqlens,
|
| 967 |
+
cu_seqlens_cpu=cu_seqlens_cpu,
|
| 968 |
+
chunk_indices=chunk_indices,
|
| 969 |
+
chunk_size=chunk_size,
|
| 970 |
+
layout_fallback=ctx.layout_fallback,
|
| 971 |
+
)
|
| 972 |
+
return y, final_state
|
| 973 |
+
|
| 974 |
+
@staticmethod
|
| 975 |
+
@input_guard(no_guard_contiguous=["dy"])
|
| 976 |
+
def backward(ctx, dy: torch.Tensor, dht: torch.Tensor | None = None) -> tuple[torch.Tensor | None, ...]:
|
| 977 |
+
x, weight, bias, residual, initial_state = ctx.saved_tensors
|
| 978 |
+
dx, dw, db, dr, dh0 = causal_conv1d_bwd(
|
| 979 |
+
x=x,
|
| 980 |
+
dy=dy,
|
| 981 |
+
dht=dht,
|
| 982 |
+
weight=weight,
|
| 983 |
+
bias=bias,
|
| 984 |
+
residual=residual,
|
| 985 |
+
initial_state=initial_state,
|
| 986 |
+
activation=ctx.activation,
|
| 987 |
+
cu_seqlens=ctx.cu_seqlens,
|
| 988 |
+
cu_seqlens_cpu=ctx.cu_seqlens_cpu,
|
| 989 |
+
chunk_indices=ctx.chunk_indices,
|
| 990 |
+
layout_fallback=ctx.layout_fallback,
|
| 991 |
+
)
|
| 992 |
+
return dx, dw, db, dr, dh0, None, None, None, None, None, None
|
| 993 |
+
|
| 994 |
+
|
| 995 |
+
@input_guard(no_guard_contiguous=["x"])
|
| 996 |
+
def causal_conv1d(
|
| 997 |
+
x: torch.Tensor,
|
| 998 |
+
weight: torch.Tensor | None = None,
|
| 999 |
+
bias: torch.Tensor | None = None,
|
| 1000 |
+
residual: torch.Tensor | None = None,
|
| 1001 |
+
initial_state: torch.Tensor | None = None,
|
| 1002 |
+
output_final_state: bool | None = False,
|
| 1003 |
+
activation: str | None = None,
|
| 1004 |
+
backend: str | None = 'triton',
|
| 1005 |
+
cu_seqlens: torch.Tensor | None = None,
|
| 1006 |
+
cu_seqlens_cpu: torch.LongTensor | None = None,
|
| 1007 |
+
chunk_indices: torch.LongTensor | None = None,
|
| 1008 |
+
cp_context: FLACPContext | None = None,
|
| 1009 |
+
**kwargs,
|
| 1010 |
+
) -> tuple[torch.Tensor, torch.Tensor | None]:
|
| 1011 |
+
"""
|
| 1012 |
+
A causal 1D convolution implementation that powers Mamba/Mamba2 and DeltaNet architectures.
|
| 1013 |
+
|
| 1014 |
+
With a residual connection, this implements the Canon operation:
|
| 1015 |
+
https://papers.ssrn.com/sol3/papers.cfm?abstract_id=5240330.
|
| 1016 |
+
|
| 1017 |
+
Args:
|
| 1018 |
+
x (torch.Tensor):
|
| 1019 |
+
Input tensor of shape [B, T, D].
|
| 1020 |
+
weight (torch.Tensor, Optional):
|
| 1021 |
+
Weight tensor of shape [D, W]. Default: `None`.
|
| 1022 |
+
bias (torch.Tensor, Optional):
|
| 1023 |
+
Bias tensor of shape [D]. Default: `None`.
|
| 1024 |
+
residual (torch.Tensor, Optional):
|
| 1025 |
+
Residual tensor of shape [B, T, D]. Default: `None`.
|
| 1026 |
+
initial_state (torch.Tensor, Optional):
|
| 1027 |
+
Initial state tensor of shape [N, D, W],
|
| 1028 |
+
where `N` is the number of sequences in the batch and `W` is the kernel size.
|
| 1029 |
+
If provided, the initial state is used to initialize the cache. Default: `None`.
|
| 1030 |
+
output_final_state (bool, Optional):
|
| 1031 |
+
Whether to output the final state of shape [N, D, W]. Default: `False`.
|
| 1032 |
+
activation (str, Optional):
|
| 1033 |
+
Activations applied to output, only `swish`/`silu` or `None` (i.e., no activation) are supported.
|
| 1034 |
+
Default: `None`.
|
| 1035 |
+
backend (str, Optional):
|
| 1036 |
+
Specifies the backend to use for the convolution operation. Supported values are `'cuda'`, `'triton'`, and `'mix'`.
|
| 1037 |
+
Default: `'triton'`.
|
| 1038 |
+
cu_seqlens (torch.Tensor, Optional):
|
| 1039 |
+
Cumulative sequence lengths. Default: `None`.
|
| 1040 |
+
cu_seqlens_cpu (torch.LongTensor, Optional):
|
| 1041 |
+
CPU copy of the cumulative sequence lengths. Default: `None`.
|
| 1042 |
+
chunk_indices (torch.Tensor, Optional):
|
| 1043 |
+
Chunk indices for variable-length sequences. Default: `None`.
|
| 1044 |
+
cp_context (FLACPContext, Optional):
|
| 1045 |
+
Context-parallel sequence metadata. CP does not support initial or final states.
|
| 1046 |
+
CUDA CP requires contiguous layout, width 2–4, and at least `W - 1` tokens per rank.
|
| 1047 |
+
The `mix` backend uses Triton in CP mode. Default: `None`.
|
| 1048 |
+
|
| 1049 |
+
Returns:
|
| 1050 |
+
tuple[torch.Tensor, torch.Tensor | None]:
|
| 1051 |
+
Output and final state. If `output_final_state` is `False`, the final state is `None`.
|
| 1052 |
+
"""
|
| 1053 |
+
# import here to avoid circular dependencies
|
| 1054 |
+
from ...modules.causal_conv1d.backends.cuda import causal_conv1d_cuda, fast_causal_conv1d_fn
|
| 1055 |
+
from ...modules.causal_conv1d.cp import causal_conv1d_cp
|
| 1056 |
+
|
| 1057 |
+
if cp_context is not None:
|
| 1058 |
+
assert initial_state is None, "Initial state is not supported for CP"
|
| 1059 |
+
assert output_final_state is False, "Output final state is not supported for CP"
|
| 1060 |
+
output = causal_conv1d_cp(
|
| 1061 |
+
x=x,
|
| 1062 |
+
weight=weight,
|
| 1063 |
+
bias=bias,
|
| 1064 |
+
activation=activation,
|
| 1065 |
+
chunk_indices=chunk_indices,
|
| 1066 |
+
cp_context=cp_context,
|
| 1067 |
+
backend=backend,
|
| 1068 |
+
residual=residual,
|
| 1069 |
+
)
|
| 1070 |
+
return output, None
|
| 1071 |
+
|
| 1072 |
+
if backend == 'triton':
|
| 1073 |
+
y, final_state = CausalConv1dFunction.apply(
|
| 1074 |
+
x,
|
| 1075 |
+
weight,
|
| 1076 |
+
bias,
|
| 1077 |
+
residual,
|
| 1078 |
+
initial_state,
|
| 1079 |
+
output_final_state,
|
| 1080 |
+
activation,
|
| 1081 |
+
cu_seqlens,
|
| 1082 |
+
cu_seqlens_cpu,
|
| 1083 |
+
chunk_indices,
|
| 1084 |
+
)
|
| 1085 |
+
return y, final_state
|
| 1086 |
+
elif backend == 'mix':
|
| 1087 |
+
seq_idx = kwargs.get('seq_idx')
|
| 1088 |
+
return fast_causal_conv1d_fn(
|
| 1089 |
+
x=x,
|
| 1090 |
+
weight=weight,
|
| 1091 |
+
bias=bias,
|
| 1092 |
+
residual=residual,
|
| 1093 |
+
initial_state=initial_state,
|
| 1094 |
+
output_final_state=output_final_state,
|
| 1095 |
+
activation=activation,
|
| 1096 |
+
cu_seqlens=cu_seqlens,
|
| 1097 |
+
cu_seqlens_cpu=cu_seqlens_cpu,
|
| 1098 |
+
chunk_indices=chunk_indices,
|
| 1099 |
+
seq_idx=seq_idx,
|
| 1100 |
+
)
|
| 1101 |
+
elif backend == 'cuda':
|
| 1102 |
+
return causal_conv1d_cuda(
|
| 1103 |
+
x=x,
|
| 1104 |
+
weight=weight,
|
| 1105 |
+
bias=bias,
|
| 1106 |
+
residual=residual,
|
| 1107 |
+
initial_state=initial_state,
|
| 1108 |
+
output_final_state=output_final_state,
|
| 1109 |
+
activation=activation,
|
| 1110 |
+
cu_seqlens=cu_seqlens,
|
| 1111 |
+
cu_seqlens_cpu=cu_seqlens_cpu,
|
| 1112 |
+
**kwargs,
|
| 1113 |
+
)
|
| 1114 |
+
else:
|
| 1115 |
+
raise ValueError(f"Unsupported backend: {backend}")
|
| 1116 |
+
|
| 1117 |
+
|
| 1118 |
+
class ShortConvolution(nn.Conv1d):
|
| 1119 |
+
"""Depthwise causal convolution with optional activation and state caching.
|
| 1120 |
+
|
| 1121 |
+
Args:
|
| 1122 |
+
hidden_size (int):
|
| 1123 |
+
Number of input and output channels.
|
| 1124 |
+
kernel_size (int):
|
| 1125 |
+
Width of the convolution kernel.
|
| 1126 |
+
bias (bool, Optional):
|
| 1127 |
+
Whether to use a channel bias. Default: `False`.
|
| 1128 |
+
activation (str, Optional):
|
| 1129 |
+
Activation applied to the convolution output. Default: `"silu"`.
|
| 1130 |
+
backend (str, Optional):
|
| 1131 |
+
Backend selected unless overridden by `FLA_CONV_BACKEND`. Default: `"triton"`.
|
| 1132 |
+
device (torch.device, Optional):
|
| 1133 |
+
Device for the parameters. Default: `None`.
|
| 1134 |
+
dtype (torch.dtype, Optional):
|
| 1135 |
+
Parameter dtype. Default: `None`.
|
| 1136 |
+
**kwargs:
|
| 1137 |
+
Accepts the deprecated `use_fast_conv1d` option.
|
| 1138 |
+
"""
|
| 1139 |
+
|
| 1140 |
+
def __init__(
|
| 1141 |
+
self,
|
| 1142 |
+
hidden_size: int,
|
| 1143 |
+
kernel_size: int,
|
| 1144 |
+
bias: bool = False,
|
| 1145 |
+
activation: str | None = 'silu',
|
| 1146 |
+
backend: str | None = 'triton',
|
| 1147 |
+
device: torch.device | None = None,
|
| 1148 |
+
dtype: torch.dtype | None = None,
|
| 1149 |
+
**kwargs,
|
| 1150 |
+
) -> None:
|
| 1151 |
+
super().__init__(
|
| 1152 |
+
in_channels=hidden_size,
|
| 1153 |
+
out_channels=hidden_size,
|
| 1154 |
+
kernel_size=kernel_size,
|
| 1155 |
+
padding=kernel_size - 1,
|
| 1156 |
+
groups=hidden_size,
|
| 1157 |
+
bias=bias,
|
| 1158 |
+
device=device,
|
| 1159 |
+
dtype=dtype,
|
| 1160 |
+
)
|
| 1161 |
+
|
| 1162 |
+
self.hidden_size = hidden_size
|
| 1163 |
+
self.activation = None
|
| 1164 |
+
|
| 1165 |
+
if activation is not None:
|
| 1166 |
+
assert activation in ['silu', 'swish'], f"Activation `{activation}` not supported yet."
|
| 1167 |
+
self.activation = activation
|
| 1168 |
+
|
| 1169 |
+
if 'use_fast_conv1d' in kwargs:
|
| 1170 |
+
warnings.warn(
|
| 1171 |
+
"The `use_fast_conv1d` parameter is deprecated and will be ignored. "
|
| 1172 |
+
"Please use the `backend` parameter instead.",
|
| 1173 |
+
)
|
| 1174 |
+
self.backend = os.environ.get('FLA_CONV_BACKEND', backend)
|
| 1175 |
+
if self.backend not in ['cuda', 'triton']:
|
| 1176 |
+
raise ValueError(f"Invalid backend: {self.backend}, must be one of ['cuda', 'triton']")
|
| 1177 |
+
if self.backend == 'cuda':
|
| 1178 |
+
if causal_conv1d_fn_cuda is None:
|
| 1179 |
+
warnings.warn(
|
| 1180 |
+
"The `backend` parameter is set to `cuda`, but `causal_conv1d_fn` is not available. "
|
| 1181 |
+
"Switching to the Triton implementation instead. "
|
| 1182 |
+
"Consider installing `causal_conv1d` to enable the CUDA backend.",
|
| 1183 |
+
)
|
| 1184 |
+
self.backend = 'triton'
|
| 1185 |
+
|
| 1186 |
+
def extra_repr(self) -> str:
|
| 1187 |
+
s = '{in_channels}, {out_channels}, kernel_size={kernel_size}, stride={stride}'
|
| 1188 |
+
if self.padding != (0,) * len(self.padding):
|
| 1189 |
+
s += ', padding={padding}'
|
| 1190 |
+
if self.dilation != (1,) * len(self.dilation):
|
| 1191 |
+
s += ', dilation={dilation}'
|
| 1192 |
+
if self.output_padding != (0,) * len(self.output_padding):
|
| 1193 |
+
s += ', output_padding={output_padding}'
|
| 1194 |
+
if self.groups != 1:
|
| 1195 |
+
s += ', groups={groups}'
|
| 1196 |
+
if self.bias is None:
|
| 1197 |
+
s += ', bias=False'
|
| 1198 |
+
if self.padding_mode != 'zeros':
|
| 1199 |
+
s += ', padding_mode={padding_mode}'
|
| 1200 |
+
if self.activation is not None:
|
| 1201 |
+
s += ', activation={activation}'
|
| 1202 |
+
s += f', backend={self.backend}'
|
| 1203 |
+
return s.format(**self.__dict__)
|
| 1204 |
+
|
| 1205 |
+
def forward(
|
| 1206 |
+
self,
|
| 1207 |
+
x: torch.Tensor,
|
| 1208 |
+
residual: torch.Tensor | None = None,
|
| 1209 |
+
mask: torch.Tensor | None = None,
|
| 1210 |
+
cache: torch.Tensor | None = None,
|
| 1211 |
+
output_final_state: bool = False,
|
| 1212 |
+
cu_seqlens: torch.LongTensor | None = None,
|
| 1213 |
+
chunk_indices: torch.LongTensor | None = None,
|
| 1214 |
+
**kwargs,
|
| 1215 |
+
) -> tuple[torch.Tensor, torch.Tensor | None]:
|
| 1216 |
+
"""
|
| 1217 |
+
Args:
|
| 1218 |
+
x (torch.Tensor):
|
| 1219 |
+
Tensor of shape `[B, T, D]`. `B` must be 1 if `cu_seqlens` is provided.
|
| 1220 |
+
residual (torch.Tensor, Optional):
|
| 1221 |
+
Residual tensor of shape `[B, T, D]`. Default: `None`.
|
| 1222 |
+
mask (torch.Tensor, Optional):
|
| 1223 |
+
Attention mask for padded positions. Default: `None`.
|
| 1224 |
+
cache (torch.Tensor, Optional):
|
| 1225 |
+
Previous cache of shape `[N, D, W]`, where `W` is the kernel size. Default: `None`.
|
| 1226 |
+
Single-token calls without autograd update it **inplace**.
|
| 1227 |
+
Other calls return the updated state when `output_final_state=True`.
|
| 1228 |
+
output_final_state (bool, Optional):
|
| 1229 |
+
Whether to output the final state of shape `[N, D, W]`. Default: `False`.
|
| 1230 |
+
cu_seqlens (torch.Tensor, Optional):
|
| 1231 |
+
Cumulative sequence lengths of shape `[N+1]`. Default: `None`.
|
| 1232 |
+
chunk_indices (torch.Tensor, Optional):
|
| 1233 |
+
Chunk indices for variable-length sequences. Default: `None`.
|
| 1234 |
+
|
| 1235 |
+
Returns:
|
| 1236 |
+
y (torch.Tensor):
|
| 1237 |
+
Convolution output of shape `[B, T, D]`.
|
| 1238 |
+
final_state (torch.Tensor, Optional):
|
| 1239 |
+
Cache of shape `[N, D, W]` when requested, otherwise `None`.
|
| 1240 |
+
"""
|
| 1241 |
+
B, T, *_ = x.shape
|
| 1242 |
+
N = B if cu_seqlens is None else len(cu_seqlens) - 1
|
| 1243 |
+
if mask is not None:
|
| 1244 |
+
if cu_seqlens is not None:
|
| 1245 |
+
raise ValueError("`mask` and `cu_seqlens` cannot be provided at the same time")
|
| 1246 |
+
x = x.mul_(mask.unsqueeze(-1))
|
| 1247 |
+
|
| 1248 |
+
# the in-place decode kernel requires autograd off and exactly one token per sequence, including packed inputs.
|
| 1249 |
+
if not torch.is_grad_enabled() and B * T == N and (cu_seqlens is None or bool((cu_seqlens.diff() == 1).all())):
|
| 1250 |
+
y, cache = self.step(
|
| 1251 |
+
x=x,
|
| 1252 |
+
residual=residual,
|
| 1253 |
+
cache=cache,
|
| 1254 |
+
output_final_state=output_final_state,
|
| 1255 |
+
cu_seqlens=cu_seqlens,
|
| 1256 |
+
)
|
| 1257 |
+
return y, cache
|
| 1258 |
+
|
| 1259 |
+
# use Triton for stateful calls unsupported by the CUDA backend.
|
| 1260 |
+
if self.backend == 'cuda' and cache is not None:
|
| 1261 |
+
warnings.warn(
|
| 1262 |
+
"The CUDA backend does not support both `cu_seqlens` and `cache` being provided, "
|
| 1263 |
+
"or both `cu_seqlens` and `output_final_state` being provided. "
|
| 1264 |
+
"Switching to the Triton backend instead. ",
|
| 1265 |
+
stacklevel=2,
|
| 1266 |
+
)
|
| 1267 |
+
self.backend = 'triton'
|
| 1268 |
+
|
| 1269 |
+
return causal_conv1d(
|
| 1270 |
+
x=x,
|
| 1271 |
+
weight=rearrange(self.weight, "d 1 w -> d w"),
|
| 1272 |
+
bias=self.bias,
|
| 1273 |
+
residual=residual,
|
| 1274 |
+
initial_state=cache,
|
| 1275 |
+
output_final_state=output_final_state,
|
| 1276 |
+
activation=self.activation,
|
| 1277 |
+
backend=self.backend,
|
| 1278 |
+
cu_seqlens=cu_seqlens,
|
| 1279 |
+
chunk_indices=chunk_indices,
|
| 1280 |
+
**kwargs,
|
| 1281 |
+
)
|
| 1282 |
+
|
| 1283 |
+
def step(
|
| 1284 |
+
self,
|
| 1285 |
+
x: torch.Tensor,
|
| 1286 |
+
residual: torch.Tensor | None,
|
| 1287 |
+
cache: torch.Tensor | None,
|
| 1288 |
+
output_final_state: bool = False,
|
| 1289 |
+
cu_seqlens: torch.LongTensor | None = None,
|
| 1290 |
+
) -> tuple[torch.Tensor, torch.Tensor | None]:
|
| 1291 |
+
B, _, D, W = *x.shape, self.kernel_size[0]
|
| 1292 |
+
N = B if cu_seqlens is None else len(cu_seqlens) - 1
|
| 1293 |
+
# the update kernel requires a cache even when the final state is not requested.
|
| 1294 |
+
if cache is None:
|
| 1295 |
+
cache = x.new_zeros(N, D, W)
|
| 1296 |
+
if self.backend == 'triton':
|
| 1297 |
+
y, cache = causal_conv1d_update(
|
| 1298 |
+
x=x,
|
| 1299 |
+
cache=cache,
|
| 1300 |
+
residual=residual,
|
| 1301 |
+
weight=rearrange(self.weight, "d 1 w -> d w"),
|
| 1302 |
+
bias=self.bias,
|
| 1303 |
+
activation=self.activation,
|
| 1304 |
+
)
|
| 1305 |
+
return y, (cache if output_final_state else None)
|
| 1306 |
+
|
| 1307 |
+
shape = x.shape
|
| 1308 |
+
x = x.squeeze(0) if cu_seqlens is not None else x.squeeze(1)
|
| 1309 |
+
# the CUDA update mutates cache in place.
|
| 1310 |
+
y = causal_conv1d_update_cuda(
|
| 1311 |
+
x=x,
|
| 1312 |
+
conv_state=cache,
|
| 1313 |
+
weight=rearrange(self.weight, "d 1 w -> d w"),
|
| 1314 |
+
bias=self.bias,
|
| 1315 |
+
activation=self.activation,
|
| 1316 |
+
)
|
| 1317 |
+
y = y.view(shape)
|
| 1318 |
+
if residual is not None:
|
| 1319 |
+
y.add_(residual)
|
| 1320 |
+
return y, (cache if output_final_state else None)
|
| 1321 |
+
|
| 1322 |
+
@property
|
| 1323 |
+
def state_size(self) -> int:
|
| 1324 |
+
return self.hidden_size * self.kernel_size[0]
|
build/torch-cuda/modules/conv/causal_conv1d.py
DELETED
|
@@ -1,129 +0,0 @@
|
|
| 1 |
-
# Copyright (c) 2023-2026, Songlin Yang, Yu Zhang, Zhiyuan Li
|
| 2 |
-
#
|
| 3 |
-
# This source code is licensed under the MIT license found in the
|
| 4 |
-
# LICENSE file in the root directory of this source tree.
|
| 5 |
-
# For a list of all contributors, visit:
|
| 6 |
-
# https://github.com/fla-org/flash-linear-attention/graphs/contributors
|
| 7 |
-
|
| 8 |
-
"""Main interface for causal 1D convolution operations."""
|
| 9 |
-
|
| 10 |
-
import torch
|
| 11 |
-
|
| 12 |
-
from ...ops.cp import FLACPContext
|
| 13 |
-
from ...utils import input_guard
|
| 14 |
-
|
| 15 |
-
|
| 16 |
-
@input_guard(no_guard_contiguous=["x"])
|
| 17 |
-
def causal_conv1d(
|
| 18 |
-
x: torch.Tensor,
|
| 19 |
-
weight: torch.Tensor | None = None,
|
| 20 |
-
bias: torch.Tensor | None = None,
|
| 21 |
-
residual: torch.Tensor | None = None,
|
| 22 |
-
initial_state: torch.Tensor | None = None,
|
| 23 |
-
output_final_state: bool | None = False,
|
| 24 |
-
activation: str | None = None,
|
| 25 |
-
backend: str | None = 'triton',
|
| 26 |
-
cu_seqlens: torch.Tensor | None = None,
|
| 27 |
-
cu_seqlens_cpu: torch.LongTensor | None = None,
|
| 28 |
-
chunk_indices: torch.LongTensor | None = None,
|
| 29 |
-
cp_context: FLACPContext | None = None,
|
| 30 |
-
**kwargs,
|
| 31 |
-
):
|
| 32 |
-
"""
|
| 33 |
-
A causal 1D convolution implementation that powers Mamba/Mamba2 and DeltaNet architectures.
|
| 34 |
-
|
| 35 |
-
When a residual connection is provided, this implements the Canon operation
|
| 36 |
-
described in the paper at https://papers.ssrn.com/sol3/papers.cfm?abstract_id=5240330.
|
| 37 |
-
|
| 38 |
-
Args:
|
| 39 |
-
x (torch.Tensor):
|
| 40 |
-
Input tensor of shape [B, T, D].
|
| 41 |
-
weight (Optional[torch.Tensor]):
|
| 42 |
-
Weight tensor of shape [D, W]. Default: `None`.
|
| 43 |
-
bias (Optional[torch.Tensor]):
|
| 44 |
-
Bias tensor of shape [D]. Default: `None`.
|
| 45 |
-
residual (Optional[torch.Tensor]):
|
| 46 |
-
Residual tensor of shape [B, T, D]. Default: `None`.
|
| 47 |
-
initial_state (Optional[torch.Tensor]):
|
| 48 |
-
Initial state tensor of shape [N, D, W],
|
| 49 |
-
where `N` is the number of sequences in the batch and `W` is the kernel size.
|
| 50 |
-
If provided, the initial state is used to initialize the cache. Default: `None`.
|
| 51 |
-
output_final_state (Optional[bool]):
|
| 52 |
-
Whether to output the final state of shape [N, D, W]. Default: `False`.
|
| 53 |
-
activation (Optional[str]):
|
| 54 |
-
Activations applied to output, only `swish`/`silu` or `None` (i.e., no activation) are supported.
|
| 55 |
-
Default: `None`.
|
| 56 |
-
backend (Optional[str]):
|
| 57 |
-
Specifies the backend to use for the convolution operation. Supported values are `'cuda'` 、 `'triton'` and `'mix'`.
|
| 58 |
-
Default: `'triton'`.
|
| 59 |
-
cu_seqlens (Optional[torch.Tensor]):
|
| 60 |
-
Cumulative sequence lengths (optional)
|
| 61 |
-
chunk_indices (Optional[torch.LongTensor]):
|
| 62 |
-
Chunk indices for variable-length sequences (optional)
|
| 63 |
-
|
| 64 |
-
Returns:
|
| 65 |
-
Tuple of (output, final_state).
|
| 66 |
-
If `output_final_state` is `False`, the final state is `None`.
|
| 67 |
-
"""
|
| 68 |
-
# Import here to avoid circular dependencies
|
| 69 |
-
from ...modules.conv.cp import causal_conv1d_cp
|
| 70 |
-
from ...modules.conv.cuda import causal_conv1d_cuda, fast_causal_conv1d_fn
|
| 71 |
-
from ...modules.conv.triton import CausalConv1dFunction
|
| 72 |
-
|
| 73 |
-
if cp_context is not None:
|
| 74 |
-
assert initial_state is None, "Initial state is not supported for CP"
|
| 75 |
-
assert output_final_state is False, "Output final state is not supported for CP"
|
| 76 |
-
output = causal_conv1d_cp(
|
| 77 |
-
x=x,
|
| 78 |
-
weight=weight,
|
| 79 |
-
bias=bias,
|
| 80 |
-
activation=activation,
|
| 81 |
-
chunk_indices=chunk_indices,
|
| 82 |
-
cp_context=cp_context,
|
| 83 |
-
)
|
| 84 |
-
return output, None
|
| 85 |
-
|
| 86 |
-
if backend == 'triton':
|
| 87 |
-
y, final_state = CausalConv1dFunction.apply(
|
| 88 |
-
x,
|
| 89 |
-
weight,
|
| 90 |
-
bias,
|
| 91 |
-
residual,
|
| 92 |
-
initial_state,
|
| 93 |
-
output_final_state,
|
| 94 |
-
activation,
|
| 95 |
-
cu_seqlens,
|
| 96 |
-
cu_seqlens_cpu,
|
| 97 |
-
chunk_indices,
|
| 98 |
-
)
|
| 99 |
-
return y, final_state
|
| 100 |
-
elif backend == 'mix':
|
| 101 |
-
seq_idx = kwargs.get('seq_idx')
|
| 102 |
-
return fast_causal_conv1d_fn(
|
| 103 |
-
x,
|
| 104 |
-
weight,
|
| 105 |
-
bias,
|
| 106 |
-
residual,
|
| 107 |
-
initial_state,
|
| 108 |
-
output_final_state,
|
| 109 |
-
activation,
|
| 110 |
-
cu_seqlens,
|
| 111 |
-
cu_seqlens_cpu=cu_seqlens_cpu,
|
| 112 |
-
chunk_indices=chunk_indices,
|
| 113 |
-
seq_idx=seq_idx,
|
| 114 |
-
)
|
| 115 |
-
elif backend == 'cuda':
|
| 116 |
-
return causal_conv1d_cuda(
|
| 117 |
-
x,
|
| 118 |
-
weight,
|
| 119 |
-
bias,
|
| 120 |
-
residual,
|
| 121 |
-
initial_state,
|
| 122 |
-
output_final_state,
|
| 123 |
-
activation,
|
| 124 |
-
cu_seqlens,
|
| 125 |
-
cu_seqlens_cpu=cu_seqlens_cpu,
|
| 126 |
-
**kwargs,
|
| 127 |
-
)
|
| 128 |
-
else:
|
| 129 |
-
raise ValueError(f"Unsupported backend: {backend}")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
build/torch-cuda/modules/conv/cuda/ops.py
DELETED
|
@@ -1,233 +0,0 @@
|
|
| 1 |
-
# Copyright (c) 2023-2026, Songlin Yang, Yu Zhang, Zhiyuan Li
|
| 2 |
-
#
|
| 3 |
-
# This source code is licensed under the MIT license found in the
|
| 4 |
-
# LICENSE file in the root directory of this source tree.
|
| 5 |
-
# For a list of all contributors, visit:
|
| 6 |
-
# https://github.com/fla-org/flash-linear-attention/graphs/contributors
|
| 7 |
-
|
| 8 |
-
"""CUDA-based mixed-mode implementation for causal convolution."""
|
| 9 |
-
|
| 10 |
-
import torch
|
| 11 |
-
from einops import rearrange
|
| 12 |
-
|
| 13 |
-
from ....modules.conv.triton import causal_conv1d_update_states
|
| 14 |
-
from ....ops.utils import prepare_sequence_ids
|
| 15 |
-
from ....utils import input_guard
|
| 16 |
-
|
| 17 |
-
try:
|
| 18 |
-
from causal_conv1d.cpp_functions import causal_conv1d_bwd_function
|
| 19 |
-
except ImportError:
|
| 20 |
-
causal_conv1d_bwd_function = None
|
| 21 |
-
|
| 22 |
-
try:
|
| 23 |
-
from causal_conv1d import causal_conv1d_fn as causal_conv1d_fn_cuda
|
| 24 |
-
except ImportError:
|
| 25 |
-
causal_conv1d_fn_cuda = None
|
| 26 |
-
|
| 27 |
-
|
| 28 |
-
class FastCausalConv1dFn(torch.autograd.Function):
|
| 29 |
-
"""
|
| 30 |
-
Mixed-mode (Mix) Causal Convolution Implementation - Combining Triton Forward and CUDA Backward Propagation
|
| 31 |
-
|
| 32 |
-
This class implements forward propagation using FLA's Triton kernel, while using the optimized
|
| 33 |
-
implementation from TriDao's causal_conv1d CUDA package for backward propagation.
|
| 34 |
-
This hybrid strategy combines the advantages of both technologies:
|
| 35 |
-
|
| 36 |
-
- Forward: Uses FLA's Triton implementation, optimized for the FLA framework
|
| 37 |
-
- Backward: Uses TriDao's causal_conv1d_bwd_function CUDA implementation for faster speed
|
| 38 |
-
|
| 39 |
-
Performance Benefits:
|
| 40 |
-
- CUDA backward implementation is typically faster than the Triton version, reducing training time
|
| 41 |
-
- Maintains the flexibility and compatibility of forward propagation
|
| 42 |
-
|
| 43 |
-
Note:
|
| 44 |
-
- Input/Output format is (batch, seqlen, dim)
|
| 45 |
-
- Backward propagation requires causal_conv1d package: pip install causal-conv1d
|
| 46 |
-
- Supports SILU/Swish activation functions
|
| 47 |
-
- Current limitations (not yet supported):
|
| 48 |
-
* output_final_state must be False
|
| 49 |
-
* initial_states must be None
|
| 50 |
-
* residual must be None
|
| 51 |
-
"""
|
| 52 |
-
@staticmethod
|
| 53 |
-
@input_guard(no_guard_contiguous=["x"])
|
| 54 |
-
def forward(
|
| 55 |
-
ctx,
|
| 56 |
-
x,
|
| 57 |
-
weight,
|
| 58 |
-
bias=None,
|
| 59 |
-
residual: torch.Tensor | None = None,
|
| 60 |
-
initial_states=None,
|
| 61 |
-
output_final_state=False,
|
| 62 |
-
activation=None,
|
| 63 |
-
cu_seqlens: torch.LongTensor | None = None,
|
| 64 |
-
cu_seqlens_cpu: torch.LongTensor | None = None,
|
| 65 |
-
chunk_indices: torch.LongTensor | None = None,
|
| 66 |
-
seq_idx: torch.LongTensor | None = None,
|
| 67 |
-
):
|
| 68 |
-
if activation not in [None, "silu", "swish"]:
|
| 69 |
-
raise NotImplementedError("activation must be None, silu, or swish")
|
| 70 |
-
assert output_final_state is False, "output_final_state must be False for FastCausalConv1dFn"
|
| 71 |
-
assert initial_states is None, "initial_states must be None for FastCausalConv1dFn"
|
| 72 |
-
assert residual is None, "residual must be None for FastCausalConv1dFn"
|
| 73 |
-
|
| 74 |
-
bias = bias.contiguous() if bias is not None else None
|
| 75 |
-
if cu_seqlens is not None and seq_idx is None:
|
| 76 |
-
seq_idx = prepare_sequence_ids(cu_seqlens, cu_seqlens_cpu=cu_seqlens_cpu).to(
|
| 77 |
-
torch.int32).unsqueeze(0)
|
| 78 |
-
seq_idx = seq_idx.contiguous() if seq_idx is not None else None
|
| 79 |
-
|
| 80 |
-
# Import here to avoid circular dependency
|
| 81 |
-
from ....modules.conv.triton.ops import causal_conv1d_fwd
|
| 82 |
-
|
| 83 |
-
ctx.activation = activation in ["silu", "swish"]
|
| 84 |
-
out, _ = causal_conv1d_fwd(
|
| 85 |
-
x=x,
|
| 86 |
-
weight=weight,
|
| 87 |
-
bias=bias,
|
| 88 |
-
residual=None,
|
| 89 |
-
initial_state=None,
|
| 90 |
-
output_final_state=output_final_state,
|
| 91 |
-
activation=activation,
|
| 92 |
-
cu_seqlens=cu_seqlens,
|
| 93 |
-
cu_seqlens_cpu=cu_seqlens_cpu,
|
| 94 |
-
chunk_indices=chunk_indices,
|
| 95 |
-
)
|
| 96 |
-
|
| 97 |
-
ctx.save_for_backward(x, weight, bias, seq_idx, initial_states)
|
| 98 |
-
ctx.return_final_states = output_final_state
|
| 99 |
-
ctx.return_dinitial_states = (
|
| 100 |
-
initial_states is not None and initial_states.requires_grad
|
| 101 |
-
)
|
| 102 |
-
return out, None
|
| 103 |
-
|
| 104 |
-
@staticmethod
|
| 105 |
-
@input_guard
|
| 106 |
-
def backward(ctx, dout, *args):
|
| 107 |
-
x, weight, bias, seq_idx, initial_states = ctx.saved_tensors
|
| 108 |
-
dx = torch.empty_like(x, memory_format=torch.contiguous_format)
|
| 109 |
-
x = rearrange(x, 'b t d -> b d t')
|
| 110 |
-
dx = rearrange(dx, 'b t d -> b d t')
|
| 111 |
-
dout = rearrange(dout, 'b t d -> b d t')
|
| 112 |
-
dfinal_states = args[0] if ctx.return_final_states else None
|
| 113 |
-
|
| 114 |
-
if dout.stride(2) != 1 and dout.stride(1) != 1:
|
| 115 |
-
dout = dout.contiguous()
|
| 116 |
-
# The kernel supports passing in a pre-allocated dx (e.g., in case we want to fuse the
|
| 117 |
-
# backward of conv1d with the backward of chunk).
|
| 118 |
-
# Here we just pass in None and dx will be allocated in the C++ code.
|
| 119 |
-
dx, dweight, dbias, dinitial_states = causal_conv1d_bwd_function(
|
| 120 |
-
x,
|
| 121 |
-
weight,
|
| 122 |
-
bias,
|
| 123 |
-
dout,
|
| 124 |
-
seq_idx,
|
| 125 |
-
initial_states,
|
| 126 |
-
dfinal_states,
|
| 127 |
-
dx,
|
| 128 |
-
ctx.return_dinitial_states,
|
| 129 |
-
ctx.activation,
|
| 130 |
-
)
|
| 131 |
-
dx = rearrange(dx, 'b d t -> b t d')
|
| 132 |
-
return (
|
| 133 |
-
dx,
|
| 134 |
-
dweight,
|
| 135 |
-
dbias if bias is not None else None,
|
| 136 |
-
None,
|
| 137 |
-
None,
|
| 138 |
-
None,
|
| 139 |
-
None,
|
| 140 |
-
None,
|
| 141 |
-
None,
|
| 142 |
-
None,
|
| 143 |
-
None,
|
| 144 |
-
)
|
| 145 |
-
|
| 146 |
-
|
| 147 |
-
def fast_causal_conv1d_fn(
|
| 148 |
-
x: torch.Tensor,
|
| 149 |
-
weight: torch.Tensor | None = None,
|
| 150 |
-
bias: torch.Tensor | None = None,
|
| 151 |
-
residual: torch.Tensor | None = None,
|
| 152 |
-
initial_state: torch.Tensor | None = None,
|
| 153 |
-
output_final_state: bool | None = False,
|
| 154 |
-
activation: str | None = None,
|
| 155 |
-
cu_seqlens: torch.Tensor | None = None,
|
| 156 |
-
cu_seqlens_cpu: torch.LongTensor | None = None,
|
| 157 |
-
chunk_indices: torch.LongTensor | None = None,
|
| 158 |
-
seq_idx: torch.LongTensor | None = None,
|
| 159 |
-
):
|
| 160 |
-
"""
|
| 161 |
-
x: (batch, seqlen, dim)
|
| 162 |
-
weight: (dim, width)
|
| 163 |
-
bias: (dim,)
|
| 164 |
-
seq_idx: (batch, seqlen)
|
| 165 |
-
initial_states: (batch, dim, width - 1)
|
| 166 |
-
final_states_out: (batch, dim, width - 1), to be written to
|
| 167 |
-
activation: either None or "silu" or "swish"
|
| 168 |
-
|
| 169 |
-
out: (batch, seqlen, dim)
|
| 170 |
-
"""
|
| 171 |
-
assert causal_conv1d_bwd_function is not None, "causal_conv1d_bwd_function is not available"
|
| 172 |
-
return FastCausalConv1dFn.apply(
|
| 173 |
-
x,
|
| 174 |
-
weight,
|
| 175 |
-
bias,
|
| 176 |
-
residual,
|
| 177 |
-
initial_state,
|
| 178 |
-
output_final_state,
|
| 179 |
-
activation,
|
| 180 |
-
cu_seqlens,
|
| 181 |
-
cu_seqlens_cpu,
|
| 182 |
-
chunk_indices,
|
| 183 |
-
seq_idx,
|
| 184 |
-
)
|
| 185 |
-
|
| 186 |
-
|
| 187 |
-
def causal_conv1d_cuda(
|
| 188 |
-
x: torch.Tensor,
|
| 189 |
-
weight: torch.Tensor,
|
| 190 |
-
bias: torch.Tensor | None = None,
|
| 191 |
-
residual: torch.Tensor | None = None,
|
| 192 |
-
initial_state: torch.Tensor | None = None,
|
| 193 |
-
output_final_state: bool | None = False,
|
| 194 |
-
activation: str | None = None,
|
| 195 |
-
cu_seqlens: torch.Tensor | None = None,
|
| 196 |
-
cu_seqlens_cpu: torch.LongTensor | None = None,
|
| 197 |
-
**kwargs,
|
| 198 |
-
):
|
| 199 |
-
assert causal_conv1d_fn_cuda is not None, "causal_conv1d_fn_cuda is not available"
|
| 200 |
-
seq_idx = kwargs.get('seq_idx')
|
| 201 |
-
if cu_seqlens is not None or seq_idx is not None:
|
| 202 |
-
assert initial_state is None, "For CUDA backend, initial_state must be None if cu_seqlens or seq_idx is provided"
|
| 203 |
-
W = weight.shape[-1]
|
| 204 |
-
if x.stride(-1) != 1:
|
| 205 |
-
x = x.contiguous()
|
| 206 |
-
x_conv1d = rearrange(x, 'b t d -> b d t')
|
| 207 |
-
if cu_seqlens is not None and seq_idx is None:
|
| 208 |
-
seq_idx = prepare_sequence_ids(cu_seqlens, cu_seqlens_cpu=cu_seqlens_cpu).to(torch.int32).unsqueeze(0)
|
| 209 |
-
|
| 210 |
-
y = causal_conv1d_fn_cuda(
|
| 211 |
-
x=x_conv1d,
|
| 212 |
-
weight=weight,
|
| 213 |
-
bias=bias,
|
| 214 |
-
activation=activation,
|
| 215 |
-
seq_idx=seq_idx,
|
| 216 |
-
initial_states=None,
|
| 217 |
-
return_final_states=False,
|
| 218 |
-
)
|
| 219 |
-
|
| 220 |
-
y = rearrange(y, 'b d t -> b t d')
|
| 221 |
-
if output_final_state:
|
| 222 |
-
final_state = causal_conv1d_update_states(
|
| 223 |
-
x=x,
|
| 224 |
-
state_len=W,
|
| 225 |
-
initial_state=initial_state,
|
| 226 |
-
cu_seqlens=cu_seqlens,
|
| 227 |
-
)
|
| 228 |
-
else:
|
| 229 |
-
final_state = None
|
| 230 |
-
if residual is not None:
|
| 231 |
-
y.add_(residual)
|
| 232 |
-
|
| 233 |
-
return y, final_state
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
build/torch-cuda/modules/conv/short_conv.py
DELETED
|
@@ -1,250 +0,0 @@
|
|
| 1 |
-
# Copyright (c) 2023-2026, Songlin Yang, Yu Zhang, Zhiyuan Li
|
| 2 |
-
#
|
| 3 |
-
# This source code is licensed under the MIT license found in the
|
| 4 |
-
# LICENSE file in the root directory of this source tree.
|
| 5 |
-
# For a list of all contributors, visit:
|
| 6 |
-
# https://github.com/fla-org/flash-linear-attention/graphs/contributors
|
| 7 |
-
|
| 8 |
-
"""Short convolution implementation for efficient causal convolutions."""
|
| 9 |
-
|
| 10 |
-
import warnings
|
| 11 |
-
|
| 12 |
-
import torch
|
| 13 |
-
import torch.nn as nn
|
| 14 |
-
from einops import rearrange
|
| 15 |
-
|
| 16 |
-
try:
|
| 17 |
-
from causal_conv1d import causal_conv1d_fn as causal_conv1d_fn_cuda
|
| 18 |
-
from causal_conv1d import causal_conv1d_update as causal_conv1d_update_cuda
|
| 19 |
-
except ImportError:
|
| 20 |
-
causal_conv1d_fn_cuda = None
|
| 21 |
-
causal_conv1d_update_cuda = None
|
| 22 |
-
|
| 23 |
-
|
| 24 |
-
class ShortConvolution(nn.Conv1d):
|
| 25 |
-
"""Short convolution layer for efficient causal convolution operations.
|
| 26 |
-
|
| 27 |
-
This class implements a depthwise 1D convolution with causal padding,
|
| 28 |
-
designed for efficient sequence processing. It supports multiple backends (Triton/CUDA)
|
| 29 |
-
and optional activation functions.
|
| 30 |
-
|
| 31 |
-
Args:
|
| 32 |
-
hidden_size (int): Number of input/output channels (must be equal for depthwise conv)
|
| 33 |
-
kernel_size (int): Size of the convolution kernel
|
| 34 |
-
bias (bool, optional): Whether to include learnable bias. Defaults to False.
|
| 35 |
-
activation (Optional[str], optional): Activation function ('silu' or 'swish'). Defaults to 'silu'.
|
| 36 |
-
backend (Optional[str], optional): Backend implementation ('triton' or 'cuda'). Defaults to 'triton'.
|
| 37 |
-
device (Optional[torch.device], optional): Device to place the layer on. Defaults to None.
|
| 38 |
-
dtype (Optional[torch.dtype], optional): Data type for layer parameters. Defaults to None.
|
| 39 |
-
**kwargs: Additional keyword arguments (deprecated 'use_fast_conv1d' supported for compatibility)
|
| 40 |
-
|
| 41 |
-
Attributes:
|
| 42 |
-
hidden_size (int): Number of channels
|
| 43 |
-
activation (Optional[str]): Selected activation function
|
| 44 |
-
backend (str): Actual backend being used (may differ from input due to availability)
|
| 45 |
-
|
| 46 |
-
Note:
|
| 47 |
-
- Uses depthwise convolution (groups=hidden_size) for efficiency
|
| 48 |
-
- Applies causal padding (kernel_size-1) to ensure no future information leakage
|
| 49 |
-
- Falls back to Triton backend if CUDA backend is unavailable
|
| 50 |
-
"""
|
| 51 |
-
|
| 52 |
-
def __init__(
|
| 53 |
-
self,
|
| 54 |
-
hidden_size: int,
|
| 55 |
-
kernel_size: int,
|
| 56 |
-
bias: bool = False,
|
| 57 |
-
activation: str | None = 'silu',
|
| 58 |
-
backend: str | None = 'triton',
|
| 59 |
-
device: torch.device | None = None,
|
| 60 |
-
dtype: torch.dtype | None = None,
|
| 61 |
-
**kwargs,
|
| 62 |
-
):
|
| 63 |
-
super().__init__(
|
| 64 |
-
in_channels=hidden_size,
|
| 65 |
-
out_channels=hidden_size,
|
| 66 |
-
kernel_size=kernel_size,
|
| 67 |
-
groups=hidden_size,
|
| 68 |
-
bias=bias,
|
| 69 |
-
padding=kernel_size - 1,
|
| 70 |
-
device=device,
|
| 71 |
-
dtype=dtype,
|
| 72 |
-
)
|
| 73 |
-
|
| 74 |
-
self.hidden_size = hidden_size
|
| 75 |
-
self.activation = None
|
| 76 |
-
|
| 77 |
-
if activation is not None:
|
| 78 |
-
assert activation in ['silu', 'swish'], f"Activation `{activation}` not supported yet."
|
| 79 |
-
self.activation = activation
|
| 80 |
-
|
| 81 |
-
if 'use_fast_conv1d' in kwargs:
|
| 82 |
-
warnings.warn(
|
| 83 |
-
"The `use_fast_conv1d` parameter is deprecated and will be ignored. "
|
| 84 |
-
"Please use the `backend` parameter instead.",
|
| 85 |
-
)
|
| 86 |
-
import os
|
| 87 |
-
self.backend = os.environ.get('FLA_CONV_BACKEND', backend)
|
| 88 |
-
if backend not in ['cuda', 'triton']:
|
| 89 |
-
raise ValueError(f"Invalid backend: {backend}, must be one of ['cuda', 'triton']")
|
| 90 |
-
if backend == 'cuda':
|
| 91 |
-
if causal_conv1d_fn_cuda is None:
|
| 92 |
-
warnings.warn(
|
| 93 |
-
"The `backend` parameter is set to `cuda`, but `causal_conv1d_fn` is not available. "
|
| 94 |
-
"Switching to the Triton implementation instead. "
|
| 95 |
-
"Consider installing `causal_conv1d` to enable the CUDA backend.",
|
| 96 |
-
)
|
| 97 |
-
self.backend = 'triton'
|
| 98 |
-
|
| 99 |
-
def extra_repr(self):
|
| 100 |
-
s = ('{in_channels}, {out_channels}, kernel_size={kernel_size}'
|
| 101 |
-
', stride={stride}')
|
| 102 |
-
if self.padding != (0,) * len(self.padding):
|
| 103 |
-
s += ', padding={padding}'
|
| 104 |
-
if self.dilation != (1,) * len(self.dilation):
|
| 105 |
-
s += ', dilation={dilation}'
|
| 106 |
-
if self.output_padding != (0,) * len(self.output_padding):
|
| 107 |
-
s += ', output_padding={output_padding}'
|
| 108 |
-
if self.groups != 1:
|
| 109 |
-
s += ', groups={groups}'
|
| 110 |
-
if self.bias is None:
|
| 111 |
-
s += ', bias=False'
|
| 112 |
-
if self.padding_mode != 'zeros':
|
| 113 |
-
s += ', padding_mode={padding_mode}'
|
| 114 |
-
if self.activation is not None:
|
| 115 |
-
s += ', activation={activation}'
|
| 116 |
-
s += f', backend={self.backend}'
|
| 117 |
-
return s.format(**self.__dict__)
|
| 118 |
-
|
| 119 |
-
def forward(
|
| 120 |
-
self,
|
| 121 |
-
x: torch.Tensor,
|
| 122 |
-
residual: torch.Tensor | None = None,
|
| 123 |
-
mask: torch.Tensor | None = None,
|
| 124 |
-
cache: torch.Tensor | None = None,
|
| 125 |
-
output_final_state: bool = False,
|
| 126 |
-
cu_seqlens: torch.LongTensor | None = None,
|
| 127 |
-
chunk_indices: torch.LongTensor | None = None,
|
| 128 |
-
**kwargs,
|
| 129 |
-
) -> tuple[torch.Tensor, torch.Tensor | None]:
|
| 130 |
-
"""
|
| 131 |
-
Args:
|
| 132 |
-
x (`torch.Tensor`):
|
| 133 |
-
Tensor of shape `[B, T, D]`. `B` must be 1 if `cu_seqlens` is provided.
|
| 134 |
-
residual (`Optional[torch.Tensor]`):
|
| 135 |
-
Residual tensor of shape `[B, T, D]`. Default: `None`.
|
| 136 |
-
mask (`Optional[torch.Tensor]`):
|
| 137 |
-
Attention mask dealing with padded positions.
|
| 138 |
-
cache (`Optional[torch.Tensor]`):
|
| 139 |
-
Previous cache tensor of shape `[N, D, W]`, where `W` is the kernel size.
|
| 140 |
-
If provided, the cache is updated **inplace**.
|
| 141 |
-
output_final_state (Optional[bool]):
|
| 142 |
-
Whether to output the final state of shape `[N, D, W]`. Default: `False`.
|
| 143 |
-
cu_seqlens (Optional[torch.LongTensor]):
|
| 144 |
-
Cumulative sequence lengths for each batch. Used for varlen. Default: `None`.
|
| 145 |
-
Shape: [B+1]
|
| 146 |
-
chunk_indices (Optional[torch.LongTensor]):
|
| 147 |
-
Chunk indices for variable-length sequences. Default: `None`.
|
| 148 |
-
|
| 149 |
-
Returns:
|
| 150 |
-
Tensor of shape `[B, T, D]`.
|
| 151 |
-
"""
|
| 152 |
-
# Import here to avoid circular dependency
|
| 153 |
-
from ...modules.conv.causal_conv1d import causal_conv1d
|
| 154 |
-
|
| 155 |
-
B, T, *_ = x.shape
|
| 156 |
-
N = B if cu_seqlens is None else len(cu_seqlens) - 1
|
| 157 |
-
if mask is not None:
|
| 158 |
-
if cu_seqlens is not None:
|
| 159 |
-
raise ValueError("`mask` and `cu_seqlens` cannot be provided at the same time")
|
| 160 |
-
x = x.mul_(mask.unsqueeze(-1))
|
| 161 |
-
|
| 162 |
-
# in decoding phase, the cache (if provided) is updated inplace
|
| 163 |
-
if B * T == N:
|
| 164 |
-
y, cache = self.step(
|
| 165 |
-
x=x,
|
| 166 |
-
residual=residual,
|
| 167 |
-
cache=cache,
|
| 168 |
-
output_final_state=output_final_state,
|
| 169 |
-
cu_seqlens=cu_seqlens,
|
| 170 |
-
)
|
| 171 |
-
return y, cache
|
| 172 |
-
|
| 173 |
-
# cuda backend do not support:
|
| 174 |
-
# 1. both `cu_seqlens` and `cache` being provided
|
| 175 |
-
# 2. both `cu_seqlens` and `output_final_state` being provided
|
| 176 |
-
# and other small issues
|
| 177 |
-
# to simplify the implementation, we just switch to triton backend
|
| 178 |
-
if self.backend == 'cuda' and cache is not None:
|
| 179 |
-
warnings.warn(
|
| 180 |
-
"The CUDA backend does not support both `cu_seqlens` and `cache` being provided, "
|
| 181 |
-
"or both `cu_seqlens` and `output_final_state` being provided. "
|
| 182 |
-
"Switching to the Triton backend instead. ",
|
| 183 |
-
stacklevel=2,
|
| 184 |
-
)
|
| 185 |
-
self.backend = 'triton'
|
| 186 |
-
|
| 187 |
-
return causal_conv1d(
|
| 188 |
-
x=x,
|
| 189 |
-
weight=rearrange(self.weight, "d 1 w -> d w"),
|
| 190 |
-
bias=self.bias,
|
| 191 |
-
residual=residual,
|
| 192 |
-
initial_state=cache,
|
| 193 |
-
output_final_state=output_final_state,
|
| 194 |
-
activation=self.activation,
|
| 195 |
-
backend=self.backend,
|
| 196 |
-
cu_seqlens=cu_seqlens,
|
| 197 |
-
chunk_indices=chunk_indices,
|
| 198 |
-
**kwargs,
|
| 199 |
-
)
|
| 200 |
-
|
| 201 |
-
def step(
|
| 202 |
-
self,
|
| 203 |
-
x: torch.Tensor,
|
| 204 |
-
residual: torch.Tensor | None,
|
| 205 |
-
cache: torch.Tensor | None,
|
| 206 |
-
output_final_state: bool = False,
|
| 207 |
-
cu_seqlens: torch.LongTensor | None = None,
|
| 208 |
-
) -> tuple[torch.Tensor, torch.Tensor | None]:
|
| 209 |
-
from ...modules.conv.triton.ops import causal_conv1d_update
|
| 210 |
-
|
| 211 |
-
B, _, D, W = *x.shape, self.kernel_size[0]
|
| 212 |
-
N = B if cu_seqlens is None else len(cu_seqlens) - 1
|
| 213 |
-
# Always initialise cache when None so the Triton kernel never
|
| 214 |
-
# receives a None tensor. Return value still respects output_final_state
|
| 215 |
-
# to maintain consistency with the non-step path in forward().
|
| 216 |
-
if cache is None:
|
| 217 |
-
cache = x.new_zeros(N, D, W)
|
| 218 |
-
# NOTE: we follow the fast mode that updates the cache in-place
|
| 219 |
-
if self.backend == 'triton':
|
| 220 |
-
y, cache = causal_conv1d_update(
|
| 221 |
-
x=x,
|
| 222 |
-
cache=cache,
|
| 223 |
-
residual=residual,
|
| 224 |
-
weight=rearrange(self.weight, "d 1 w -> d w"),
|
| 225 |
-
bias=self.bias,
|
| 226 |
-
activation=self.activation,
|
| 227 |
-
)
|
| 228 |
-
return y, (cache if output_final_state else None)
|
| 229 |
-
|
| 230 |
-
shape = x.shape
|
| 231 |
-
x = x.squeeze(0) if cu_seqlens is not None else x.squeeze(1)
|
| 232 |
-
# equivalent to:
|
| 233 |
-
# cache.copy_(cache.roll(shifts=-1, dims=-1))
|
| 234 |
-
# cache[:, :, -1] = x
|
| 235 |
-
# y = torch.sum(cache * rearrange(self.weight, "d 1 w -> d w"), dim=-1)
|
| 236 |
-
y = causal_conv1d_update_cuda(
|
| 237 |
-
x=x,
|
| 238 |
-
conv_state=cache,
|
| 239 |
-
weight=rearrange(self.weight, "d 1 w -> d w"),
|
| 240 |
-
bias=self.bias,
|
| 241 |
-
activation=self.activation,
|
| 242 |
-
)
|
| 243 |
-
y = y.view(shape)
|
| 244 |
-
if residual is not None:
|
| 245 |
-
y.add_(residual)
|
| 246 |
-
return y, (cache if output_final_state else None)
|
| 247 |
-
|
| 248 |
-
@property
|
| 249 |
-
def state_size(self) -> int:
|
| 250 |
-
return self.hidden_size * self.kernel_size
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
build/torch-cuda/modules/conv/triton/ops.py
DELETED
|
@@ -1,424 +0,0 @@
|
|
| 1 |
-
# Copyright (c) 2023-2026, Songlin Yang, Yu Zhang, Zhiyuan Li
|
| 2 |
-
#
|
| 3 |
-
# This source code is licensed under the MIT license found in the
|
| 4 |
-
# LICENSE file in the root directory of this source tree.
|
| 5 |
-
# For a list of all contributors, visit:
|
| 6 |
-
# https://github.com/fla-org/flash-linear-attention/graphs/contributors
|
| 7 |
-
|
| 8 |
-
import torch
|
| 9 |
-
import triton
|
| 10 |
-
from einops import rearrange
|
| 11 |
-
|
| 12 |
-
from ....modules.backends import dispatch
|
| 13 |
-
from ....ops.utils import prepare_chunk_indices
|
| 14 |
-
from ....utils import input_guard
|
| 15 |
-
|
| 16 |
-
from .kernels import (
|
| 17 |
-
causal_conv1d_bwd_kernel,
|
| 18 |
-
causal_conv1d_fwd_kernel,
|
| 19 |
-
causal_conv1d_states_fwd_kernel,
|
| 20 |
-
causal_conv1d_update_kernel,
|
| 21 |
-
compute_dh0_kernel,
|
| 22 |
-
)
|
| 23 |
-
|
| 24 |
-
|
| 25 |
-
def _has_non_standard_layout(x: torch.Tensor) -> bool:
|
| 26 |
-
"""QKV-style views (stride_t != D) break triton-ascend masked kernels."""
|
| 27 |
-
if x.dtype not in (torch.float16, torch.bfloat16):
|
| 28 |
-
return False
|
| 29 |
-
if x.dim() != 3:
|
| 30 |
-
return not x.is_contiguous()
|
| 31 |
-
_, stride_t, stride_d = x.stride()
|
| 32 |
-
return stride_d == 1 and stride_t != x.shape[-1]
|
| 33 |
-
|
| 34 |
-
|
| 35 |
-
@dispatch('modules')
|
| 36 |
-
@input_guard(no_guard_contiguous=["x"])
|
| 37 |
-
def causal_conv1d_fwd(
|
| 38 |
-
x: torch.Tensor,
|
| 39 |
-
weight: torch.Tensor,
|
| 40 |
-
bias: torch.Tensor,
|
| 41 |
-
residual: torch.Tensor,
|
| 42 |
-
initial_state: torch.Tensor | None = None,
|
| 43 |
-
output_final_state: bool = False,
|
| 44 |
-
activation: str | None = None,
|
| 45 |
-
cu_seqlens: torch.LongTensor | None = None,
|
| 46 |
-
cu_seqlens_cpu: torch.LongTensor | None = None,
|
| 47 |
-
chunk_indices: torch.LongTensor | None = None,
|
| 48 |
-
BT: int = 64,
|
| 49 |
-
layout_fallback: bool = False,
|
| 50 |
-
) -> torch.Tensor:
|
| 51 |
-
shape = x.shape
|
| 52 |
-
if x.shape[-1] != weight.shape[0]:
|
| 53 |
-
x = rearrange(x, 'b t ... -> b t (...)')
|
| 54 |
-
B, T, D = x.shape[0], x.shape[1], weight.shape[0]
|
| 55 |
-
W = weight.shape[1]
|
| 56 |
-
stride_x_n, stride_x_t, stride_x_d = x.stride()
|
| 57 |
-
|
| 58 |
-
BW = triton.next_power_of_2(W)
|
| 59 |
-
if cu_seqlens is not None and chunk_indices is None:
|
| 60 |
-
chunk_indices = prepare_chunk_indices(cu_seqlens, BT, cu_seqlens_cpu=cu_seqlens_cpu)
|
| 61 |
-
NT = len(chunk_indices) if cu_seqlens is not None else triton.cdiv(T, BT)
|
| 62 |
-
NB = triton.cdiv(B*T, 1024)
|
| 63 |
-
|
| 64 |
-
y = torch.empty_like(x, memory_format=torch.contiguous_format)
|
| 65 |
-
|
| 66 |
-
def grid(meta): return (triton.cdiv(D, meta['BD']), NT, B)
|
| 67 |
-
causal_conv1d_fwd_kernel[grid](
|
| 68 |
-
x=x,
|
| 69 |
-
y=y,
|
| 70 |
-
weight=weight,
|
| 71 |
-
bias=bias,
|
| 72 |
-
residual=residual,
|
| 73 |
-
cu_seqlens=cu_seqlens,
|
| 74 |
-
initial_state=initial_state,
|
| 75 |
-
chunk_indices=chunk_indices,
|
| 76 |
-
B=B,
|
| 77 |
-
T=T,
|
| 78 |
-
D=D,
|
| 79 |
-
W=W,
|
| 80 |
-
BT=BT,
|
| 81 |
-
BW=BW,
|
| 82 |
-
NB=NB,
|
| 83 |
-
stride_x_n=stride_x_n,
|
| 84 |
-
stride_x_t=stride_x_t,
|
| 85 |
-
stride_x_d=stride_x_d,
|
| 86 |
-
ACTIVATION=activation,
|
| 87 |
-
)
|
| 88 |
-
final_state = None
|
| 89 |
-
if output_final_state:
|
| 90 |
-
final_state = causal_conv1d_update_states(
|
| 91 |
-
x=x,
|
| 92 |
-
state_len=W,
|
| 93 |
-
initial_state=initial_state,
|
| 94 |
-
cu_seqlens=cu_seqlens,
|
| 95 |
-
)
|
| 96 |
-
return y.view(shape), final_state
|
| 97 |
-
|
| 98 |
-
|
| 99 |
-
@dispatch('modules')
|
| 100 |
-
def compute_dh0_triton(
|
| 101 |
-
dy: torch.Tensor,
|
| 102 |
-
y: torch.Tensor | None,
|
| 103 |
-
weight: torch.Tensor,
|
| 104 |
-
initial_state: torch.Tensor,
|
| 105 |
-
activation: str | None,
|
| 106 |
-
cu_seqlens: torch.Tensor | None,
|
| 107 |
-
) -> torch.Tensor:
|
| 108 |
-
"""
|
| 109 |
-
Compute dh0 (gradient w.r.t. initial_state) using a separate Triton kernel.
|
| 110 |
-
This is a workaround for Triton compiler bugs on some architectures (e.g., GB200).
|
| 111 |
-
"""
|
| 112 |
-
D, W = weight.shape
|
| 113 |
-
N = initial_state.shape[0]
|
| 114 |
-
T = dy.shape[1]
|
| 115 |
-
|
| 116 |
-
# Initialize dh0
|
| 117 |
-
dh0 = torch.zeros_like(initial_state)
|
| 118 |
-
|
| 119 |
-
BD = 32
|
| 120 |
-
grid = (triton.cdiv(D, BD), N)
|
| 121 |
-
|
| 122 |
-
y_to_pass = y if activation in ('swish', 'silu') else None
|
| 123 |
-
# dy is [B, T, D], stride_n = T*D, stride_t = D
|
| 124 |
-
stride_dy_n = dy.stride(0)
|
| 125 |
-
stride_dy_t = dy.stride(1)
|
| 126 |
-
|
| 127 |
-
compute_dh0_kernel[grid](
|
| 128 |
-
dy=dy,
|
| 129 |
-
y=y_to_pass,
|
| 130 |
-
weight=weight,
|
| 131 |
-
dh0=dh0,
|
| 132 |
-
cu_seqlens=cu_seqlens,
|
| 133 |
-
stride_dy_n=stride_dy_n,
|
| 134 |
-
stride_dy_t=stride_dy_t,
|
| 135 |
-
T=T,
|
| 136 |
-
D=D,
|
| 137 |
-
W=W,
|
| 138 |
-
BD=BD,
|
| 139 |
-
)
|
| 140 |
-
|
| 141 |
-
return dh0
|
| 142 |
-
|
| 143 |
-
|
| 144 |
-
@dispatch('modules')
|
| 145 |
-
def causal_conv1d_bwd(
|
| 146 |
-
x: torch.Tensor,
|
| 147 |
-
dy: torch.Tensor,
|
| 148 |
-
dht: torch.Tensor,
|
| 149 |
-
weight: torch.Tensor | None = None,
|
| 150 |
-
bias: torch.Tensor | None = None,
|
| 151 |
-
residual: torch.Tensor | None = None,
|
| 152 |
-
initial_state: torch.Tensor | None = None,
|
| 153 |
-
activation: str | None = None,
|
| 154 |
-
cu_seqlens: torch.Tensor | None = None,
|
| 155 |
-
cu_seqlens_cpu: torch.LongTensor | None = None,
|
| 156 |
-
chunk_indices: torch.LongTensor | None = None,
|
| 157 |
-
BT: int = 64,
|
| 158 |
-
layout_fallback: bool = False,
|
| 159 |
-
):
|
| 160 |
-
shape = x.shape
|
| 161 |
-
if x.shape[-1] != weight.shape[0]:
|
| 162 |
-
x = rearrange(x, 'b t ... -> b t (...)')
|
| 163 |
-
B, T, D = x.shape
|
| 164 |
-
W = weight.shape[1] if weight is not None else None
|
| 165 |
-
|
| 166 |
-
stride_x_n, stride_x_t, stride_x_d = x.stride()
|
| 167 |
-
stride_dy_n, stride_dy_t, stride_dy_d = dy.stride()
|
| 168 |
-
|
| 169 |
-
BW = triton.next_power_of_2(W)
|
| 170 |
-
if cu_seqlens is not None and chunk_indices is None:
|
| 171 |
-
chunk_indices = prepare_chunk_indices(cu_seqlens, BT, cu_seqlens_cpu=cu_seqlens_cpu)
|
| 172 |
-
NT = len(chunk_indices) if cu_seqlens is not None else triton.cdiv(T, BT)
|
| 173 |
-
NB = triton.cdiv(B*T, 1024)
|
| 174 |
-
|
| 175 |
-
y = None
|
| 176 |
-
if activation is not None:
|
| 177 |
-
y, _ = causal_conv1d_fwd(
|
| 178 |
-
x=x,
|
| 179 |
-
weight=weight,
|
| 180 |
-
bias=bias,
|
| 181 |
-
residual=None,
|
| 182 |
-
initial_state=initial_state,
|
| 183 |
-
activation=None,
|
| 184 |
-
cu_seqlens=cu_seqlens,
|
| 185 |
-
cu_seqlens_cpu=cu_seqlens_cpu,
|
| 186 |
-
output_final_state=False,
|
| 187 |
-
chunk_indices=chunk_indices,
|
| 188 |
-
)
|
| 189 |
-
dx = torch.empty_like(x)
|
| 190 |
-
dw = weight.new_empty(B*NT, *weight.shape, dtype=torch.float) if weight is not None else None
|
| 191 |
-
db = bias.new_empty(B*NT, *bias.shape, dtype=torch.float) if bias is not None else None
|
| 192 |
-
dr = dy if residual is not None else None
|
| 193 |
-
|
| 194 |
-
stride_dx_n, stride_dx_t, stride_dx_d = dx.stride()
|
| 195 |
-
|
| 196 |
-
def grid(meta): return (triton.cdiv(D, meta['BD']), NT, B)
|
| 197 |
-
causal_conv1d_bwd_kernel[grid](
|
| 198 |
-
x=x,
|
| 199 |
-
y=y,
|
| 200 |
-
weight=weight,
|
| 201 |
-
initial_state=initial_state,
|
| 202 |
-
dht=dht,
|
| 203 |
-
dy=dy,
|
| 204 |
-
dx=dx,
|
| 205 |
-
dw=dw,
|
| 206 |
-
db=db,
|
| 207 |
-
cu_seqlens=cu_seqlens,
|
| 208 |
-
chunk_indices=chunk_indices,
|
| 209 |
-
B=B,
|
| 210 |
-
T=T,
|
| 211 |
-
D=D,
|
| 212 |
-
W=W,
|
| 213 |
-
BT=BT,
|
| 214 |
-
BW=BW,
|
| 215 |
-
NB=NB,
|
| 216 |
-
stride_x_n=stride_x_n,
|
| 217 |
-
stride_x_t=stride_x_t,
|
| 218 |
-
stride_x_d=stride_x_d,
|
| 219 |
-
stride_dx_n=stride_dx_n,
|
| 220 |
-
stride_dx_t=stride_dx_t,
|
| 221 |
-
stride_dx_d=stride_dx_d,
|
| 222 |
-
stride_dy_n=stride_dy_n,
|
| 223 |
-
stride_dy_t=stride_dy_t,
|
| 224 |
-
stride_dy_d=stride_dy_d,
|
| 225 |
-
ACTIVATION=activation,
|
| 226 |
-
)
|
| 227 |
-
if weight is not None:
|
| 228 |
-
dw = dw.sum(0).to(weight)
|
| 229 |
-
if bias is not None:
|
| 230 |
-
db = db.sum(0).to(bias)
|
| 231 |
-
|
| 232 |
-
# Compute dh0 using separate Triton kernel to avoid compiler bugs on some architectures (e.g., GB200)
|
| 233 |
-
dh0 = None
|
| 234 |
-
if initial_state is not None:
|
| 235 |
-
dh0 = compute_dh0_triton(
|
| 236 |
-
dy=dy,
|
| 237 |
-
y=y,
|
| 238 |
-
weight=weight,
|
| 239 |
-
initial_state=initial_state,
|
| 240 |
-
activation=activation,
|
| 241 |
-
cu_seqlens=cu_seqlens,
|
| 242 |
-
)
|
| 243 |
-
|
| 244 |
-
return dx.view(shape), dw, db, dr, dh0
|
| 245 |
-
|
| 246 |
-
|
| 247 |
-
@dispatch('modules')
|
| 248 |
-
@input_guard(no_guard_contiguous=["x"])
|
| 249 |
-
def causal_conv1d_update_states(
|
| 250 |
-
x: torch.Tensor,
|
| 251 |
-
state_len: int,
|
| 252 |
-
initial_state: torch.Tensor | None = None,
|
| 253 |
-
cu_seqlens: torch.Tensor | None = None,
|
| 254 |
-
) -> torch.Tensor:
|
| 255 |
-
if cu_seqlens is not None:
|
| 256 |
-
N = len(cu_seqlens) - 1
|
| 257 |
-
if x.dim() == 2:
|
| 258 |
-
stride_x_n = 0
|
| 259 |
-
stride_x_t, stride_x_d = x.stride()
|
| 260 |
-
T = x.shape[0]
|
| 261 |
-
else:
|
| 262 |
-
stride_x_n = x.stride(0)
|
| 263 |
-
stride_x_t, stride_x_d = x.stride(1), x.stride(2)
|
| 264 |
-
T = x.shape[1]
|
| 265 |
-
D = x.shape[-1]
|
| 266 |
-
else:
|
| 267 |
-
B, T, D = x.shape
|
| 268 |
-
N = B
|
| 269 |
-
stride_x_n, stride_x_t, stride_x_d = x.stride()
|
| 270 |
-
|
| 271 |
-
W = state_len
|
| 272 |
-
final_state = torch.empty(N, D, W, dtype=x.dtype, device=x.device)
|
| 273 |
-
|
| 274 |
-
BD = min(triton.next_power_of_2(D), 256)
|
| 275 |
-
BW = triton.next_power_of_2(W)
|
| 276 |
-
|
| 277 |
-
grid = (triton.cdiv(D, BD), N)
|
| 278 |
-
|
| 279 |
-
causal_conv1d_states_fwd_kernel[grid](
|
| 280 |
-
x=x,
|
| 281 |
-
initial_state=initial_state,
|
| 282 |
-
final_state=final_state,
|
| 283 |
-
cu_seqlens=cu_seqlens,
|
| 284 |
-
T=T,
|
| 285 |
-
D=D,
|
| 286 |
-
W=W,
|
| 287 |
-
stride_x_n=stride_x_n,
|
| 288 |
-
stride_x_t=stride_x_t,
|
| 289 |
-
stride_x_d=stride_x_d,
|
| 290 |
-
BW=BW,
|
| 291 |
-
BD=BD,
|
| 292 |
-
)
|
| 293 |
-
return final_state
|
| 294 |
-
|
| 295 |
-
|
| 296 |
-
@dispatch('modules')
|
| 297 |
-
@input_guard(no_guard_contiguous=["x"])
|
| 298 |
-
def causal_conv1d_update(
|
| 299 |
-
x: torch.Tensor,
|
| 300 |
-
cache: torch.Tensor,
|
| 301 |
-
residual: torch.Tensor | None = None,
|
| 302 |
-
weight: torch.Tensor | None = None,
|
| 303 |
-
bias: torch.Tensor | None = None,
|
| 304 |
-
activation: str | None = None,
|
| 305 |
-
) -> torch.Tensor:
|
| 306 |
-
shape = x.shape
|
| 307 |
-
if weight is not None and x.shape[-1] != weight.shape[0]:
|
| 308 |
-
x = rearrange(x, 'b t ... -> b t (...)')
|
| 309 |
-
|
| 310 |
-
D = x.shape[-1]
|
| 311 |
-
N = x.numel() // D
|
| 312 |
-
W = weight.shape[1] if weight is not None else None
|
| 313 |
-
BW = triton.next_power_of_2(W)
|
| 314 |
-
|
| 315 |
-
if x.dim() == 2:
|
| 316 |
-
# Case: (N, D)
|
| 317 |
-
stride_x_n = x.stride(0)
|
| 318 |
-
stride_x_d = x.stride(1)
|
| 319 |
-
elif x.dim() == 3 and x.shape[0] == 1:
|
| 320 |
-
# Case: (1, N, D) -> Time=1, Batch=N, Dim=D
|
| 321 |
-
# Batch 在 dim 1
|
| 322 |
-
stride_x_n = x.stride(1)
|
| 323 |
-
stride_x_d = x.stride(2)
|
| 324 |
-
elif x.dim() == 3:
|
| 325 |
-
# Case: (N, 1, D) -> Batch=N, Time=1, Dim=D
|
| 326 |
-
# Batch 在 dim 0
|
| 327 |
-
stride_x_n = x.stride(0)
|
| 328 |
-
stride_x_d = x.stride(2)
|
| 329 |
-
else:
|
| 330 |
-
# Fallback / Error case
|
| 331 |
-
raise ValueError(f"Unsupported input shape: {x.shape}")
|
| 332 |
-
|
| 333 |
-
y = torch.empty_like(x, memory_format=torch.contiguous_format)
|
| 334 |
-
|
| 335 |
-
if y.dim() == 2:
|
| 336 |
-
stride_y_n, stride_y_d = y.stride(0), y.stride(1)
|
| 337 |
-
elif y.dim() == 3 and y.shape[0] == 1:
|
| 338 |
-
stride_y_n, stride_y_d = y.stride(1), y.stride(2)
|
| 339 |
-
elif y.dim() == 3:
|
| 340 |
-
stride_y_n, stride_y_d = y.stride(0), y.stride(2)
|
| 341 |
-
|
| 342 |
-
def grid(meta): return (triton.cdiv(D, meta['BD']), N)
|
| 343 |
-
|
| 344 |
-
causal_conv1d_update_kernel[grid](
|
| 345 |
-
x=x,
|
| 346 |
-
cache=cache,
|
| 347 |
-
residual=residual,
|
| 348 |
-
y=y,
|
| 349 |
-
weight=weight,
|
| 350 |
-
bias=bias,
|
| 351 |
-
stride_x_n=stride_x_n,
|
| 352 |
-
stride_x_d=stride_x_d,
|
| 353 |
-
stride_y_n=stride_y_n,
|
| 354 |
-
stride_y_d=stride_y_d,
|
| 355 |
-
D=D,
|
| 356 |
-
W=W,
|
| 357 |
-
BW=BW,
|
| 358 |
-
ACTIVATION=activation,
|
| 359 |
-
)
|
| 360 |
-
return y.view(shape), cache
|
| 361 |
-
|
| 362 |
-
|
| 363 |
-
class CausalConv1dFunction(torch.autograd.Function):
|
| 364 |
-
|
| 365 |
-
@staticmethod
|
| 366 |
-
@input_guard(no_guard_contiguous=["x"])
|
| 367 |
-
def forward(
|
| 368 |
-
ctx,
|
| 369 |
-
x: torch.Tensor,
|
| 370 |
-
weight: torch.Tensor | None = None,
|
| 371 |
-
bias: torch.Tensor | None = None,
|
| 372 |
-
residual: torch.Tensor | None = None,
|
| 373 |
-
initial_state: torch.Tensor | None = None,
|
| 374 |
-
output_final_state: bool | None = False,
|
| 375 |
-
activation: str | None = None,
|
| 376 |
-
cu_seqlens: torch.Tensor | None = None,
|
| 377 |
-
cu_seqlens_cpu: torch.LongTensor | None = None,
|
| 378 |
-
chunk_indices: torch.LongTensor | None = None,
|
| 379 |
-
chunk_size: int = 64,
|
| 380 |
-
):
|
| 381 |
-
BT = chunk_size
|
| 382 |
-
if cu_seqlens is not None and chunk_indices is None:
|
| 383 |
-
chunk_indices = prepare_chunk_indices(cu_seqlens, BT, cu_seqlens_cpu=cu_seqlens_cpu)
|
| 384 |
-
ctx.activation = activation
|
| 385 |
-
ctx.cu_seqlens = cu_seqlens
|
| 386 |
-
ctx.cu_seqlens_cpu = cu_seqlens_cpu
|
| 387 |
-
ctx.chunk_indices = chunk_indices
|
| 388 |
-
ctx.layout_fallback = _has_non_standard_layout(x)
|
| 389 |
-
ctx.save_for_backward(x, weight, bias, residual, initial_state)
|
| 390 |
-
y, final_state = causal_conv1d_fwd(
|
| 391 |
-
x=x,
|
| 392 |
-
weight=weight,
|
| 393 |
-
bias=bias,
|
| 394 |
-
residual=residual,
|
| 395 |
-
initial_state=initial_state,
|
| 396 |
-
output_final_state=output_final_state,
|
| 397 |
-
activation=activation,
|
| 398 |
-
cu_seqlens=cu_seqlens,
|
| 399 |
-
cu_seqlens_cpu=cu_seqlens_cpu,
|
| 400 |
-
chunk_indices=chunk_indices,
|
| 401 |
-
BT=BT,
|
| 402 |
-
layout_fallback=ctx.layout_fallback,
|
| 403 |
-
)
|
| 404 |
-
return y, final_state
|
| 405 |
-
|
| 406 |
-
@staticmethod
|
| 407 |
-
@input_guard(no_guard_contiguous=["dy"])
|
| 408 |
-
def backward(ctx, dy: torch.Tensor, dht: torch.Tensor | None = None):
|
| 409 |
-
x, weight, bias, residual, initial_state = ctx.saved_tensors
|
| 410 |
-
dx, dw, db, dr, dh0 = causal_conv1d_bwd(
|
| 411 |
-
x=x,
|
| 412 |
-
dy=dy,
|
| 413 |
-
dht=dht,
|
| 414 |
-
weight=weight,
|
| 415 |
-
bias=bias,
|
| 416 |
-
residual=residual,
|
| 417 |
-
initial_state=initial_state,
|
| 418 |
-
activation=ctx.activation,
|
| 419 |
-
cu_seqlens=ctx.cu_seqlens,
|
| 420 |
-
cu_seqlens_cpu=ctx.cu_seqlens_cpu,
|
| 421 |
-
chunk_indices=ctx.chunk_indices,
|
| 422 |
-
layout_fallback=ctx.layout_fallback,
|
| 423 |
-
)
|
| 424 |
-
return dx, dw, db, dr, dh0, None, None, None, None, None, None
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
build/torch-cuda/modules/convolution.py
DELETED
|
@@ -1,42 +0,0 @@
|
|
| 1 |
-
# Copyright (c) 2023-2026, Songlin Yang, Yu Zhang, Zhiyuan Li
|
| 2 |
-
#
|
| 3 |
-
# This source code is licensed under the MIT license found in the
|
| 4 |
-
# LICENSE file in the root directory of this source tree.
|
| 5 |
-
# For a list of all contributors, visit:
|
| 6 |
-
# https://github.com/fla-org/flash-linear-attention/graphs/contributors
|
| 7 |
-
|
| 8 |
-
from ..modules.conv import (
|
| 9 |
-
ImplicitLongConvolution,
|
| 10 |
-
LongConvolution,
|
| 11 |
-
PositionalEmbedding,
|
| 12 |
-
ShortConvolution,
|
| 13 |
-
causal_conv1d,
|
| 14 |
-
fft_conv,
|
| 15 |
-
)
|
| 16 |
-
from ..modules.conv.cp import CausalConv1dFunctionCP, causal_conv1d_cp
|
| 17 |
-
from ..modules.conv.cuda import FastCausalConv1dFn, fast_causal_conv1d_fn
|
| 18 |
-
from ..modules.conv.triton import (
|
| 19 |
-
CausalConv1dFunction,
|
| 20 |
-
causal_conv1d_bwd,
|
| 21 |
-
causal_conv1d_fwd,
|
| 22 |
-
causal_conv1d_update,
|
| 23 |
-
causal_conv1d_update_states,
|
| 24 |
-
)
|
| 25 |
-
|
| 26 |
-
__all__ = [
|
| 27 |
-
'CausalConv1dFunction',
|
| 28 |
-
'CausalConv1dFunctionCP',
|
| 29 |
-
'FastCausalConv1dFn',
|
| 30 |
-
'ImplicitLongConvolution',
|
| 31 |
-
'LongConvolution',
|
| 32 |
-
'PositionalEmbedding',
|
| 33 |
-
'ShortConvolution',
|
| 34 |
-
'causal_conv1d',
|
| 35 |
-
'causal_conv1d_bwd',
|
| 36 |
-
'causal_conv1d_cp',
|
| 37 |
-
'causal_conv1d_fwd',
|
| 38 |
-
'causal_conv1d_update',
|
| 39 |
-
'causal_conv1d_update_states',
|
| 40 |
-
'fast_causal_conv1d_fn',
|
| 41 |
-
'fft_conv',
|
| 42 |
-
]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
build/torch-cuda/modules/feature_map.py
CHANGED
|
@@ -121,8 +121,7 @@ class DPFPFeatureMap(nn.Module):
|
|
| 121 |
self.nu = nu
|
| 122 |
|
| 123 |
def forward(self, x: torch.Tensor) -> torch.Tensor:
|
| 124 |
-
|
| 125 |
-
x = torch.cat([relu, -relu], dim=-1)
|
| 126 |
x_rolled = torch.cat([x.roll(shifts=j, dims=-1) for j in range(1, self.nu+1)], dim=-1)
|
| 127 |
x_repeat = torch.cat([x] * self.nu, dim=-1)
|
| 128 |
return x_repeat * x_rolled
|
|
|
|
| 121 |
self.nu = nu
|
| 122 |
|
| 123 |
def forward(self, x: torch.Tensor) -> torch.Tensor:
|
| 124 |
+
x = torch.cat([x.relu(), (-x).relu()], dim=-1)
|
|
|
|
| 125 |
x_rolled = torch.cat([x.roll(shifts=j, dims=-1) for j in range(1, self.nu+1)], dim=-1)
|
| 126 |
x_repeat = torch.cat([x] * self.nu, dim=-1)
|
| 127 |
return x_repeat * x_rolled
|
build/torch-cuda/modules/fused_bitlinear.py
CHANGED
|
@@ -5,491 +5,42 @@
|
|
| 5 |
# For a list of all contributors, visit:
|
| 6 |
# https://github.com/fla-org/flash-linear-attention/graphs/contributors
|
| 7 |
|
| 8 |
-
#
|
| 9 |
# [The Era of 1-bit LLMs: All Large Language Models are in 1.58 Bits](https://arxiv.org/abs/2402.17764)
|
| 10 |
# [Scalable MatMul-free Language Modeling](https://arxiv.org/abs/2406.02528)
|
| 11 |
#
|
| 12 |
-
#
|
| 13 |
|
| 14 |
from __future__ import annotations
|
| 15 |
|
| 16 |
-
import math
|
| 17 |
-
|
| 18 |
import torch
|
| 19 |
import torch.nn as nn
|
| 20 |
import torch.nn.functional as F
|
| 21 |
-
import triton
|
| 22 |
-
import triton.language as tl
|
| 23 |
-
|
| 24 |
-
from ..modules.layernorm import RMSNorm
|
| 25 |
-
from ..utils import IS_AMD, autotune_cache_kwargs, get_multiprocessor_count, input_guard, require_version
|
| 26 |
-
|
| 27 |
-
NUM_WARPS_AUTOTUNE = [1, 2, 4, 8, 16] if IS_AMD else [1, 2, 4, 8, 16, 32]
|
| 28 |
|
|
|
|
|
|
|
| 29 |
|
| 30 |
-
def activation_quant(x):
|
| 31 |
-
"""
|
| 32 |
-
Per-token quantization to 8 bits. No grouping is needed for quantization.
|
| 33 |
-
|
| 34 |
-
Args:
|
| 35 |
-
x: An activation tensor with shape [n, d].
|
| 36 |
|
| 37 |
-
|
| 38 |
-
|
| 39 |
-
"""
|
| 40 |
-
# Compute the scale factor
|
| 41 |
scale = 127.0 / x.abs().max(dim=-1, keepdim=True).values.clamp_(min=1e-5)
|
| 42 |
-
|
| 43 |
-
y = (x * scale).round().clamp_(-128, 127) / scale
|
| 44 |
return y
|
| 45 |
|
| 46 |
|
| 47 |
-
def
|
| 48 |
-
"""
|
| 49 |
-
Per-tensor quantization to 1.58 bits. No grouping is needed for quantization.
|
| 50 |
-
|
| 51 |
-
Args:
|
| 52 |
-
w: A weight tensor with shape [d, k].
|
| 53 |
-
|
| 54 |
-
Returns:
|
| 55 |
-
A quantized weight tensor with shape [d, k].
|
| 56 |
-
"""
|
| 57 |
-
# Compute the scale factor
|
| 58 |
-
scale = 1.0 / w.abs().mean().clamp_(min=1e-5)
|
| 59 |
-
# Quantize and then de-quantize the tensor
|
| 60 |
-
u = (w * scale).round().clamp_(-1, 1) / scale
|
| 61 |
-
return u
|
| 62 |
-
|
| 63 |
-
|
| 64 |
-
@triton.autotune(
|
| 65 |
-
configs=[
|
| 66 |
-
triton.Config({}, num_warps=num_warps)
|
| 67 |
-
for num_warps in NUM_WARPS_AUTOTUNE
|
| 68 |
-
],
|
| 69 |
-
key=["N", "HAS_RESIDUAL", "STORE_RESIDUAL_OUT", "IS_RMS_NORM", "HAS_BIAS"],
|
| 70 |
-
**autotune_cache_kwargs,
|
| 71 |
-
)
|
| 72 |
-
@triton.jit
|
| 73 |
-
def layer_norm_fwd_kernel_quant(
|
| 74 |
-
X, # pointer to the input
|
| 75 |
-
Y, # pointer to the output
|
| 76 |
-
W, # pointer to the weights
|
| 77 |
-
B, # pointer to the biases
|
| 78 |
-
RESIDUAL, # pointer to the residual
|
| 79 |
-
RESIDUAL_OUT, # pointer to the residual
|
| 80 |
-
Mean, # pointer to the mean
|
| 81 |
-
Rstd, # pointer to the 1/std
|
| 82 |
-
stride_x_row, # how much to increase the pointer when moving by 1 row
|
| 83 |
-
stride_y_row,
|
| 84 |
-
stride_res_row,
|
| 85 |
-
stride_res_out_row,
|
| 86 |
-
N, # number of columns in X
|
| 87 |
-
eps, # epsilon to avoid division by zero
|
| 88 |
-
IS_RMS_NORM: tl.constexpr,
|
| 89 |
-
BLOCK_N: tl.constexpr,
|
| 90 |
-
HAS_RESIDUAL: tl.constexpr,
|
| 91 |
-
STORE_RESIDUAL_OUT: tl.constexpr,
|
| 92 |
-
HAS_WEIGHT: tl.constexpr,
|
| 93 |
-
HAS_BIAS: tl.constexpr,
|
| 94 |
-
):
|
| 95 |
-
# Map the program id to the row of X and Y it should compute.
|
| 96 |
-
row = tl.program_id(0)
|
| 97 |
-
X += row * stride_x_row
|
| 98 |
-
Y += row * stride_y_row
|
| 99 |
-
if HAS_RESIDUAL:
|
| 100 |
-
RESIDUAL += row * stride_res_row
|
| 101 |
-
if STORE_RESIDUAL_OUT:
|
| 102 |
-
RESIDUAL_OUT += row * stride_res_out_row
|
| 103 |
-
# Compute mean and variance
|
| 104 |
-
cols = tl.arange(0, BLOCK_N)
|
| 105 |
-
x = tl.load(X + cols, mask=cols < N, other=0.0).to(tl.float32)
|
| 106 |
-
if HAS_RESIDUAL:
|
| 107 |
-
residual = tl.load(RESIDUAL + cols, mask=cols < N, other=0.0).to(tl.float32)
|
| 108 |
-
x += residual
|
| 109 |
-
if STORE_RESIDUAL_OUT:
|
| 110 |
-
tl.store(RESIDUAL_OUT + cols, x, mask=cols < N)
|
| 111 |
-
if not IS_RMS_NORM:
|
| 112 |
-
mean = tl.sum(x, axis=0) / N
|
| 113 |
-
tl.store(Mean + row, mean)
|
| 114 |
-
xbar = tl.where(cols < N, x - mean, 0.0)
|
| 115 |
-
var = tl.sum(xbar * xbar, axis=0) / N
|
| 116 |
-
else:
|
| 117 |
-
xbar = tl.where(cols < N, x, 0.0)
|
| 118 |
-
var = tl.sum(xbar * xbar, axis=0) / N
|
| 119 |
-
rstd = 1 / tl.sqrt(var + eps)
|
| 120 |
-
tl.store(Rstd + row, rstd)
|
| 121 |
-
# Normalize and apply linear transformation
|
| 122 |
-
mask = cols < N
|
| 123 |
-
if HAS_WEIGHT:
|
| 124 |
-
w = tl.load(W + cols, mask=mask).to(tl.float32)
|
| 125 |
-
if HAS_BIAS:
|
| 126 |
-
b = tl.load(B + cols, mask=mask).to(tl.float32)
|
| 127 |
-
x_hat = (x - mean) * rstd if not IS_RMS_NORM else x * rstd
|
| 128 |
-
|
| 129 |
-
y = x_hat * w if HAS_WEIGHT else x_hat
|
| 130 |
-
if HAS_BIAS:
|
| 131 |
-
y = y + b
|
| 132 |
-
|
| 133 |
-
# Aply quantization to the output
|
| 134 |
-
scale = 127.0 / tl.maximum(tl.max(tl.abs(y), 0), 1e-5)
|
| 135 |
-
# Quantize and then de-quantize the tensor
|
| 136 |
-
y = tl.extra.cuda.libdevice.round(y * scale)
|
| 137 |
-
y = tl.maximum(tl.minimum(y, 127), -128) / scale
|
| 138 |
-
|
| 139 |
-
# Write output
|
| 140 |
-
tl.store(Y + cols, y, mask=mask)
|
| 141 |
-
|
| 142 |
-
|
| 143 |
-
def layer_norm_fwd_quant(
|
| 144 |
-
x: torch.Tensor,
|
| 145 |
-
weight: torch.Tensor,
|
| 146 |
-
bias: torch.Tensor,
|
| 147 |
-
eps: float,
|
| 148 |
-
residual: torch.Tensor = None,
|
| 149 |
-
out_dtype: torch.dtype = None,
|
| 150 |
-
residual_dtype: torch.dtype = None,
|
| 151 |
-
is_rms_norm: bool = False,
|
| 152 |
-
):
|
| 153 |
-
if residual is not None:
|
| 154 |
-
residual_dtype = residual.dtype
|
| 155 |
-
M, N = x.shape
|
| 156 |
-
# allocate output
|
| 157 |
-
y = torch.empty_like(x, dtype=x.dtype if out_dtype is None else out_dtype)
|
| 158 |
-
if residual is not None or (residual_dtype is not None and residual_dtype != x.dtype):
|
| 159 |
-
residual_out = torch.empty(M, N, device=x.device, dtype=residual_dtype)
|
| 160 |
-
else:
|
| 161 |
-
residual_out = None
|
| 162 |
-
mean = torch.empty((M,), dtype=torch.float32, device=x.device) if not is_rms_norm else None
|
| 163 |
-
rstd = torch.empty((M,), dtype=torch.float32, device=x.device)
|
| 164 |
-
# Less than 64KB per feature: enqueue fused kernel
|
| 165 |
-
MAX_FUSED_SIZE = 65536 // x.element_size()
|
| 166 |
-
BLOCK_N = min(MAX_FUSED_SIZE, triton.next_power_of_2(N))
|
| 167 |
-
if N > BLOCK_N:
|
| 168 |
-
raise RuntimeError("This layer norm doesn't support feature dim >= 64KB.")
|
| 169 |
-
# heuristics for number of warps
|
| 170 |
-
layer_norm_fwd_kernel_quant[(M,)](
|
| 171 |
-
x,
|
| 172 |
-
y,
|
| 173 |
-
weight,
|
| 174 |
-
bias,
|
| 175 |
-
residual,
|
| 176 |
-
residual_out,
|
| 177 |
-
mean,
|
| 178 |
-
rstd,
|
| 179 |
-
x.stride(0),
|
| 180 |
-
y.stride(0),
|
| 181 |
-
residual.stride(0) if residual is not None else 0,
|
| 182 |
-
residual_out.stride(0) if residual_out is not None else 0,
|
| 183 |
-
N,
|
| 184 |
-
eps,
|
| 185 |
-
is_rms_norm,
|
| 186 |
-
BLOCK_N,
|
| 187 |
-
residual is not None,
|
| 188 |
-
residual_out is not None,
|
| 189 |
-
weight is not None,
|
| 190 |
-
bias is not None,
|
| 191 |
-
)
|
| 192 |
-
# residual_out is None if residual is None and residual_dtype == input_dtype
|
| 193 |
-
return y, mean, rstd, residual_out if residual_out is not None else x
|
| 194 |
-
|
| 195 |
-
|
| 196 |
-
@triton.heuristics({
|
| 197 |
-
"RECOMPUTE_OUTPUT": lambda args: args["Y"] is not None,
|
| 198 |
-
})
|
| 199 |
-
@triton.autotune(
|
| 200 |
-
configs=[
|
| 201 |
-
triton.Config({}, num_warps=num_warps)
|
| 202 |
-
for num_warps in NUM_WARPS_AUTOTUNE
|
| 203 |
-
],
|
| 204 |
-
key=["N", "HAS_DRESIDUAL", "STORE_DRESIDUAL", "IS_RMS_NORM", "HAS_BIAS"],
|
| 205 |
-
**autotune_cache_kwargs,
|
| 206 |
-
)
|
| 207 |
-
@triton.jit
|
| 208 |
-
def layer_norm_bwd_kernel(
|
| 209 |
-
X, # pointer to the input
|
| 210 |
-
W, # pointer to the weights
|
| 211 |
-
B, # pointer to the biases
|
| 212 |
-
Y, # pointer to the output to be recomputed
|
| 213 |
-
DY, # pointer to the output gradient
|
| 214 |
-
DX, # pointer to the input gradient
|
| 215 |
-
DW, # pointer to the partial sum of weights gradient
|
| 216 |
-
DB, # pointer to the partial sum of biases gradient
|
| 217 |
-
DRESIDUAL,
|
| 218 |
-
DRESIDUAL_IN,
|
| 219 |
-
Mean, # pointer to the mean
|
| 220 |
-
Rstd, # pointer to the 1/std
|
| 221 |
-
stride_x_row, # how much to increase the pointer when moving by 1 row
|
| 222 |
-
stride_y_row,
|
| 223 |
-
stride_dy_row,
|
| 224 |
-
stride_dx_row,
|
| 225 |
-
stride_dres_row,
|
| 226 |
-
stride_dres_in_row,
|
| 227 |
-
M, # number of rows in X
|
| 228 |
-
N, # number of columns in X
|
| 229 |
-
eps, # epsilon to avoid division by zero
|
| 230 |
-
rows_per_program,
|
| 231 |
-
IS_RMS_NORM: tl.constexpr,
|
| 232 |
-
BLOCK_N: tl.constexpr,
|
| 233 |
-
HAS_DRESIDUAL: tl.constexpr,
|
| 234 |
-
STORE_DRESIDUAL: tl.constexpr,
|
| 235 |
-
HAS_WEIGHT: tl.constexpr,
|
| 236 |
-
HAS_BIAS: tl.constexpr,
|
| 237 |
-
RECOMPUTE_OUTPUT: tl.constexpr,
|
| 238 |
-
):
|
| 239 |
-
# Map the program id to the elements of X, DX, and DY it should compute.
|
| 240 |
-
row_block_id = tl.program_id(0)
|
| 241 |
-
row_start = row_block_id * rows_per_program
|
| 242 |
-
cols = tl.arange(0, BLOCK_N)
|
| 243 |
-
mask = cols < N
|
| 244 |
-
X += row_start * stride_x_row
|
| 245 |
-
if HAS_DRESIDUAL:
|
| 246 |
-
DRESIDUAL += row_start * stride_dres_row
|
| 247 |
-
if STORE_DRESIDUAL:
|
| 248 |
-
DRESIDUAL_IN += row_start * stride_dres_in_row
|
| 249 |
-
DY += row_start * stride_dy_row
|
| 250 |
-
DX += row_start * stride_dx_row
|
| 251 |
-
if RECOMPUTE_OUTPUT:
|
| 252 |
-
Y += row_start * stride_y_row
|
| 253 |
-
if HAS_WEIGHT:
|
| 254 |
-
w = tl.load(W + cols, mask=mask).to(tl.float32)
|
| 255 |
-
dw = tl.zeros((BLOCK_N,), dtype=tl.float32)
|
| 256 |
-
if RECOMPUTE_OUTPUT and HAS_BIAS:
|
| 257 |
-
b = tl.load(B + cols, mask=mask, other=0.0).to(tl.float32)
|
| 258 |
-
if HAS_BIAS:
|
| 259 |
-
db = tl.zeros((BLOCK_N,), dtype=tl.float32)
|
| 260 |
-
row_end = min((row_block_id + 1) * rows_per_program, M)
|
| 261 |
-
for row in range(row_start, row_end):
|
| 262 |
-
# Load data to SRAM
|
| 263 |
-
x = tl.load(X + cols, mask=mask, other=0).to(tl.float32)
|
| 264 |
-
dy = tl.load(DY + cols, mask=mask, other=0).to(tl.float32)
|
| 265 |
-
if not IS_RMS_NORM:
|
| 266 |
-
mean = tl.load(Mean + row)
|
| 267 |
-
rstd = tl.load(Rstd + row)
|
| 268 |
-
# Compute dx
|
| 269 |
-
xhat = (x - mean) * rstd if not IS_RMS_NORM else x * rstd
|
| 270 |
-
xhat = tl.where(mask, xhat, 0.0)
|
| 271 |
-
if RECOMPUTE_OUTPUT:
|
| 272 |
-
y = xhat * w if HAS_WEIGHT else xhat
|
| 273 |
-
if HAS_BIAS:
|
| 274 |
-
y = y + b
|
| 275 |
-
|
| 276 |
-
# Aply quantization to the output
|
| 277 |
-
scale = 127.0 / tl.maximum(tl.max(tl.abs(y), 0), 1e-5)
|
| 278 |
-
# Quantize and then de-quantize the tensor
|
| 279 |
-
y = tl.extra.cuda.libdevice.round(y * scale)
|
| 280 |
-
y = tl.maximum(tl.minimum(y, 127), -128) / scale
|
| 281 |
-
|
| 282 |
-
tl.store(Y + cols, y, mask=mask)
|
| 283 |
-
wdy = dy
|
| 284 |
-
if HAS_WEIGHT:
|
| 285 |
-
wdy = dy * w
|
| 286 |
-
dw += dy * xhat
|
| 287 |
-
if HAS_BIAS:
|
| 288 |
-
db += dy
|
| 289 |
-
if not IS_RMS_NORM:
|
| 290 |
-
c1 = tl.sum(xhat * wdy, axis=0) / N
|
| 291 |
-
c2 = tl.sum(wdy, axis=0) / N
|
| 292 |
-
dx = (wdy - (xhat * c1 + c2)) * rstd
|
| 293 |
-
else:
|
| 294 |
-
c1 = tl.sum(xhat * wdy, axis=0) / N
|
| 295 |
-
dx = (wdy - xhat * c1) * rstd
|
| 296 |
-
if HAS_DRESIDUAL:
|
| 297 |
-
dres = tl.load(DRESIDUAL + cols, mask=mask, other=0).to(tl.float32)
|
| 298 |
-
dx += dres
|
| 299 |
-
# Write dx
|
| 300 |
-
if STORE_DRESIDUAL:
|
| 301 |
-
tl.store(DRESIDUAL_IN + cols, dx, mask=mask)
|
| 302 |
-
tl.store(DX + cols, dx, mask=mask)
|
| 303 |
-
|
| 304 |
-
X += stride_x_row
|
| 305 |
-
if HAS_DRESIDUAL:
|
| 306 |
-
DRESIDUAL += stride_dres_row
|
| 307 |
-
if STORE_DRESIDUAL:
|
| 308 |
-
DRESIDUAL_IN += stride_dres_in_row
|
| 309 |
-
if RECOMPUTE_OUTPUT:
|
| 310 |
-
Y += stride_y_row
|
| 311 |
-
DY += stride_dy_row
|
| 312 |
-
DX += stride_dx_row
|
| 313 |
-
if HAS_WEIGHT:
|
| 314 |
-
tl.store(DW + row_block_id * N + cols, dw, mask=mask)
|
| 315 |
-
if HAS_BIAS:
|
| 316 |
-
tl.store(DB + row_block_id * N + cols, db, mask=mask)
|
| 317 |
-
|
| 318 |
-
|
| 319 |
-
def layer_norm_bwd(
|
| 320 |
-
dy: torch.Tensor,
|
| 321 |
x: torch.Tensor,
|
| 322 |
-
|
| 323 |
-
|
| 324 |
-
|
| 325 |
-
|
| 326 |
-
|
| 327 |
-
|
| 328 |
-
|
|
|
|
| 329 |
is_rms_norm: bool = False,
|
| 330 |
-
|
| 331 |
-
|
| 332 |
-
):
|
| 333 |
-
M, N = x.shape
|
| 334 |
-
# allocate output
|
| 335 |
-
dx = torch.empty_like(x) if x_dtype is None else torch.empty(M, N, dtype=x_dtype, device=x.device)
|
| 336 |
-
dresidual_in = torch.empty_like(x) if has_residual and dx.dtype != x.dtype else None
|
| 337 |
-
y = torch.empty(M, N, dtype=dy.dtype, device=dy.device) if recompute_output else None
|
| 338 |
-
|
| 339 |
-
# Less than 64KB per feature: enqueue fused kernel
|
| 340 |
-
MAX_FUSED_SIZE = 65536 // x.element_size()
|
| 341 |
-
BLOCK_N = min(MAX_FUSED_SIZE, triton.next_power_of_2(N))
|
| 342 |
-
if N > BLOCK_N:
|
| 343 |
-
raise RuntimeError("This layer norm doesn't support feature dim >= 64KB.")
|
| 344 |
-
sm_count = get_multiprocessor_count(x.device.index)
|
| 345 |
-
_dw = torch.empty((sm_count, N), dtype=torch.float32, device=weight.device) if weight is not None else None
|
| 346 |
-
_db = torch.empty((sm_count, N), dtype=torch.float32, device=bias.device) if bias is not None else None
|
| 347 |
-
rows_per_program = math.ceil(M / sm_count)
|
| 348 |
-
grid = (sm_count,)
|
| 349 |
-
layer_norm_bwd_kernel[grid](
|
| 350 |
-
x,
|
| 351 |
-
weight,
|
| 352 |
-
bias,
|
| 353 |
-
y,
|
| 354 |
-
dy,
|
| 355 |
-
dx,
|
| 356 |
-
_dw,
|
| 357 |
-
_db,
|
| 358 |
-
dresidual,
|
| 359 |
-
dresidual_in,
|
| 360 |
-
mean,
|
| 361 |
-
rstd,
|
| 362 |
-
x.stride(0),
|
| 363 |
-
0 if not recompute_output else y.stride(0),
|
| 364 |
-
dy.stride(0),
|
| 365 |
-
dx.stride(0),
|
| 366 |
-
dresidual.stride(0) if dresidual is not None else 0,
|
| 367 |
-
dresidual_in.stride(0) if dresidual_in is not None else 0,
|
| 368 |
-
M,
|
| 369 |
-
N,
|
| 370 |
-
eps,
|
| 371 |
-
rows_per_program,
|
| 372 |
-
is_rms_norm,
|
| 373 |
-
BLOCK_N,
|
| 374 |
-
dresidual is not None,
|
| 375 |
-
dresidual_in is not None,
|
| 376 |
-
weight is not None,
|
| 377 |
-
bias is not None,
|
| 378 |
-
)
|
| 379 |
-
dw = _dw.sum(0).to(weight.dtype) if weight is not None else None
|
| 380 |
-
db = _db.sum(0).to(bias.dtype) if bias is not None else None
|
| 381 |
-
# Don't need to compute dresidual_in separately in this case
|
| 382 |
-
if has_residual and dx.dtype == x.dtype:
|
| 383 |
-
dresidual_in = dx
|
| 384 |
-
return (dx, dw, db, dresidual_in) if not recompute_output else (dx, dw, db, dresidual_in, y)
|
| 385 |
-
|
| 386 |
-
|
| 387 |
-
class LayerNormLinearQuantFn(torch.autograd.Function):
|
| 388 |
-
|
| 389 |
-
@staticmethod
|
| 390 |
-
@input_guard
|
| 391 |
-
def forward(
|
| 392 |
-
ctx,
|
| 393 |
-
x,
|
| 394 |
-
norm_weight,
|
| 395 |
-
norm_bias,
|
| 396 |
-
linear_weight,
|
| 397 |
-
linear_bias,
|
| 398 |
-
residual=None,
|
| 399 |
-
eps=1e-6,
|
| 400 |
-
prenorm=False,
|
| 401 |
-
residual_in_fp32=False,
|
| 402 |
-
is_rms_norm=False,
|
| 403 |
-
):
|
| 404 |
-
x_shape_og = x.shape
|
| 405 |
-
# reshape input data into 2D tensor
|
| 406 |
-
x = x.reshape(-1, x.shape[-1])
|
| 407 |
-
if residual is not None:
|
| 408 |
-
assert residual.shape == x_shape_og
|
| 409 |
-
residual = residual.reshape(-1, residual.shape[-1])
|
| 410 |
-
residual_dtype = residual.dtype if residual is not None else (torch.float32 if residual_in_fp32 else None)
|
| 411 |
-
y, mean, rstd, residual_out = layer_norm_fwd_quant(
|
| 412 |
-
x,
|
| 413 |
-
norm_weight,
|
| 414 |
-
norm_bias,
|
| 415 |
-
eps,
|
| 416 |
-
residual,
|
| 417 |
-
out_dtype=None if not torch.is_autocast_enabled() else torch.get_autocast_gpu_dtype(),
|
| 418 |
-
residual_dtype=residual_dtype,
|
| 419 |
-
is_rms_norm=is_rms_norm,
|
| 420 |
-
)
|
| 421 |
-
y = y.reshape(x_shape_og)
|
| 422 |
-
dtype = torch.get_autocast_gpu_dtype() if torch.is_autocast_enabled() else y.dtype
|
| 423 |
-
linear_weight = weight_quant(linear_weight).to(dtype)
|
| 424 |
-
linear_bias = linear_bias.to(dtype) if linear_bias is not None else None
|
| 425 |
-
out = F.linear(y.to(linear_weight.dtype), linear_weight, linear_bias)
|
| 426 |
-
# We don't store y, will be recomputed in the backward pass to save memory
|
| 427 |
-
ctx.save_for_backward(residual_out, norm_weight, norm_bias, linear_weight, mean, rstd)
|
| 428 |
-
ctx.x_shape_og = x_shape_og
|
| 429 |
-
ctx.eps = eps
|
| 430 |
-
ctx.is_rms_norm = is_rms_norm
|
| 431 |
-
ctx.has_residual = residual is not None
|
| 432 |
-
ctx.prenorm = prenorm
|
| 433 |
-
ctx.x_dtype = x.dtype
|
| 434 |
-
ctx.linear_bias_is_none = linear_bias is None
|
| 435 |
-
return out if not prenorm else (out, residual_out.reshape(x_shape_og))
|
| 436 |
-
|
| 437 |
-
@staticmethod
|
| 438 |
-
@input_guard
|
| 439 |
-
def backward(ctx, dout, *args):
|
| 440 |
-
x, norm_weight, norm_bias, linear_weight, mean, rstd = ctx.saved_tensors
|
| 441 |
-
dout = dout.reshape(-1, dout.shape[-1])
|
| 442 |
-
dy = F.linear(dout, linear_weight.t())
|
| 443 |
-
dlinear_bias = None if ctx.linear_bias_is_none else dout.sum(0)
|
| 444 |
-
assert dy.shape == x.shape
|
| 445 |
-
if ctx.prenorm:
|
| 446 |
-
dresidual = args[0]
|
| 447 |
-
dresidual = dresidual.reshape(-1, dresidual.shape[-1])
|
| 448 |
-
assert dresidual.shape == x.shape
|
| 449 |
-
else:
|
| 450 |
-
dresidual = None
|
| 451 |
-
dx, dnorm_weight, dnorm_bias, dresidual_in, y = layer_norm_bwd(
|
| 452 |
-
dy,
|
| 453 |
-
x,
|
| 454 |
-
norm_weight,
|
| 455 |
-
norm_bias,
|
| 456 |
-
ctx.eps,
|
| 457 |
-
mean,
|
| 458 |
-
rstd,
|
| 459 |
-
dresidual,
|
| 460 |
-
ctx.has_residual,
|
| 461 |
-
ctx.is_rms_norm,
|
| 462 |
-
x_dtype=ctx.x_dtype,
|
| 463 |
-
recompute_output=True,
|
| 464 |
-
)
|
| 465 |
-
dlinear_weight = torch.einsum("bo,bi->oi", dout, y)
|
| 466 |
-
return (
|
| 467 |
-
dx.reshape(ctx.x_shape_og),
|
| 468 |
-
dnorm_weight,
|
| 469 |
-
dnorm_bias,
|
| 470 |
-
dlinear_weight,
|
| 471 |
-
dlinear_bias,
|
| 472 |
-
dresidual_in.reshape(ctx.x_shape_og) if ctx.has_residual else None,
|
| 473 |
-
None,
|
| 474 |
-
None,
|
| 475 |
-
None,
|
| 476 |
-
None,
|
| 477 |
-
)
|
| 478 |
-
|
| 479 |
-
|
| 480 |
-
def layer_norm_linear_quant_fn(
|
| 481 |
-
x,
|
| 482 |
-
norm_weight,
|
| 483 |
-
norm_bias,
|
| 484 |
-
linear_weight,
|
| 485 |
-
linear_bias,
|
| 486 |
-
residual=None,
|
| 487 |
-
eps=1e-6,
|
| 488 |
-
prenorm=False,
|
| 489 |
-
residual_in_fp32=False,
|
| 490 |
-
is_rms_norm=False,
|
| 491 |
-
):
|
| 492 |
-
return LayerNormLinearQuantFn.apply(
|
| 493 |
x,
|
| 494 |
norm_weight,
|
| 495 |
norm_bias,
|
|
@@ -505,16 +56,16 @@ def layer_norm_linear_quant_fn(
|
|
| 505 |
|
| 506 |
def rms_norm_linear_quant(
|
| 507 |
x: torch.Tensor,
|
| 508 |
-
norm_weight: torch.Tensor,
|
| 509 |
-
norm_bias: torch.Tensor,
|
| 510 |
linear_weight: torch.Tensor,
|
| 511 |
-
linear_bias: torch.Tensor,
|
| 512 |
-
residual: torch.Tensor = None,
|
| 513 |
eps: float = 1e-5,
|
| 514 |
prenorm: bool = False,
|
| 515 |
residual_in_fp32: bool = False,
|
| 516 |
-
):
|
| 517 |
-
return
|
| 518 |
x=x,
|
| 519 |
norm_weight=norm_weight,
|
| 520 |
norm_bias=norm_bias,
|
|
@@ -528,111 +79,77 @@ def rms_norm_linear_quant(
|
|
| 528 |
)
|
| 529 |
|
| 530 |
|
| 531 |
-
|
| 532 |
-
|
| 533 |
-
|
| 534 |
-
|
| 535 |
-
|
| 536 |
-
|
| 537 |
-
|
| 538 |
-
|
| 539 |
-
|
| 540 |
-
|
| 541 |
-
|
| 542 |
-
|
| 543 |
-
|
| 544 |
-
|
| 545 |
-
|
| 546 |
-
|
| 547 |
-
return layer_norm_linear_quant_fn(
|
| 548 |
-
x,
|
| 549 |
-
norm_weight,
|
| 550 |
-
norm_bias,
|
| 551 |
-
weight,
|
| 552 |
-
bias,
|
| 553 |
is_rms_norm=True,
|
| 554 |
)
|
| 555 |
|
| 556 |
|
| 557 |
class BitLinear(nn.Linear):
|
| 558 |
"""
|
| 559 |
-
|
| 560 |
-
|
| 561 |
-
|
|
|
|
| 562 |
|
| 563 |
-
|
| 564 |
-
|
| 565 |
-
|
| 566 |
-
out_features
|
| 567 |
-
|
| 568 |
-
|
| 569 |
-
|
| 570 |
-
|
| 571 |
-
|
|
|
|
| 572 |
|
| 573 |
-
|
| 574 |
-
|
| 575 |
-
out_features: Size of each output sample.
|
| 576 |
-
bias: If set to False, the layer will not learn an additive bias. Default: True.
|
| 577 |
-
"""
|
| 578 |
-
# Initialize the superclass nn.Linear with the given parameters
|
| 579 |
-
super().__init__(in_features, out_features, bias=bias)
|
| 580 |
|
| 581 |
-
self.norm = RMSNorm(in_features, eps=norm_eps, dtype=torch.float32)
|
| 582 |
|
| 583 |
def __repr__(self) -> str:
|
| 584 |
return f"{self.__class__.__name__}({super().extra_repr()}, norm_eps={self.norm.eps})"
|
| 585 |
|
| 586 |
-
def forward(self, x):
|
| 587 |
-
"""
|
| 588 |
-
Overrides the forward pass to include quantization.
|
| 589 |
-
|
| 590 |
-
Args:
|
| 591 |
-
x: An input tensor with shape [n, d].
|
| 592 |
-
|
| 593 |
-
Returns:
|
| 594 |
-
An output tensor with shape [n, d].
|
| 595 |
-
"""
|
| 596 |
-
# Weight tensor
|
| 597 |
w = self.weight
|
|
|
|
| 598 |
|
| 599 |
-
#
|
| 600 |
-
x_norm =
|
| 601 |
-
|
| 602 |
-
|
| 603 |
-
# Uses Straight-Through Estimator (STE) trick with .detach() for gradient flow
|
| 604 |
-
x_quant = x_norm + (activation_quant(x_norm) - x_norm).detach()
|
| 605 |
-
w_quant = w + (weight_quant(w) - w).detach()
|
| 606 |
-
# Perform linear operation with quantized values
|
| 607 |
-
y = F.linear(x_quant, w_quant)
|
| 608 |
|
| 609 |
return y
|
| 610 |
|
| 611 |
|
| 612 |
class FusedBitLinear(BitLinear):
|
| 613 |
-
"""
|
| 614 |
-
|
| 615 |
-
|
| 616 |
-
|
| 617 |
-
|
| 618 |
-
def
|
| 619 |
-
|
| 620 |
-
|
| 621 |
-
|
| 622 |
-
|
| 623 |
-
|
| 624 |
-
|
| 625 |
-
|
| 626 |
-
"""
|
| 627 |
-
# Initialize the superclass nn.Linear with the given parameters
|
| 628 |
-
super().__init__(in_features, out_features, bias=bias)
|
| 629 |
-
|
| 630 |
-
def forward(self, x):
|
| 631 |
-
return layer_norm_linear_quant_fn(
|
| 632 |
-
x,
|
| 633 |
-
self.norm.weight,
|
| 634 |
-
self.norm.bias,
|
| 635 |
-
self.weight,
|
| 636 |
-
self.bias,
|
| 637 |
is_rms_norm=True,
|
| 638 |
)
|
|
|
|
| 5 |
# For a list of all contributors, visit:
|
| 6 |
# https://github.com/fla-org/flash-linear-attention/graphs/contributors
|
| 7 |
|
| 8 |
+
# BitLinear with fused normalization and quantized linear projection.
|
| 9 |
# [The Era of 1-bit LLMs: All Large Language Models are in 1.58 Bits](https://arxiv.org/abs/2402.17764)
|
| 10 |
# [Scalable MatMul-free Language Modeling](https://arxiv.org/abs/2406.02528)
|
| 11 |
#
|
| 12 |
+
# adapted from https://github.com/ridgerchu/matmulfreellm/
|
| 13 |
|
| 14 |
from __future__ import annotations
|
| 15 |
|
|
|
|
|
|
|
| 16 |
import torch
|
| 17 |
import torch.nn as nn
|
| 18 |
import torch.nn.functional as F
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 19 |
|
| 20 |
+
from ..modules.norm import RMSNorm
|
| 21 |
+
from ..modules.norm.layernorm_quant import LayerNormLinearQuantFunction, weight_quant
|
| 22 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 23 |
|
| 24 |
+
def activation_quant(x: torch.Tensor) -> torch.Tensor:
|
| 25 |
+
"""Quantize activations to 8 bits per token and return dequantized values."""
|
|
|
|
|
|
|
| 26 |
scale = 127.0 / x.abs().max(dim=-1, keepdim=True).values.clamp_(min=1e-5)
|
| 27 |
+
y = (x * scale).round().clamp_(min=-128, max=127) / scale
|
|
|
|
| 28 |
return y
|
| 29 |
|
| 30 |
|
| 31 |
+
def layer_norm_linear_quant(
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 32 |
x: torch.Tensor,
|
| 33 |
+
norm_weight: torch.Tensor | None,
|
| 34 |
+
norm_bias: torch.Tensor | None,
|
| 35 |
+
linear_weight: torch.Tensor,
|
| 36 |
+
linear_bias: torch.Tensor | None,
|
| 37 |
+
residual: torch.Tensor | None = None,
|
| 38 |
+
eps: float = 1e-6,
|
| 39 |
+
prenorm: bool = False,
|
| 40 |
+
residual_in_fp32: bool = False,
|
| 41 |
is_rms_norm: bool = False,
|
| 42 |
+
) -> torch.Tensor | tuple[torch.Tensor, torch.Tensor]:
|
| 43 |
+
return LayerNormLinearQuantFunction.apply(
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 44 |
x,
|
| 45 |
norm_weight,
|
| 46 |
norm_bias,
|
|
|
|
| 56 |
|
| 57 |
def rms_norm_linear_quant(
|
| 58 |
x: torch.Tensor,
|
| 59 |
+
norm_weight: torch.Tensor | None,
|
| 60 |
+
norm_bias: torch.Tensor | None,
|
| 61 |
linear_weight: torch.Tensor,
|
| 62 |
+
linear_bias: torch.Tensor | None,
|
| 63 |
+
residual: torch.Tensor | None = None,
|
| 64 |
eps: float = 1e-5,
|
| 65 |
prenorm: bool = False,
|
| 66 |
residual_in_fp32: bool = False,
|
| 67 |
+
) -> torch.Tensor | tuple[torch.Tensor, torch.Tensor]:
|
| 68 |
+
return layer_norm_linear_quant(
|
| 69 |
x=x,
|
| 70 |
norm_weight=norm_weight,
|
| 71 |
norm_bias=norm_bias,
|
|
|
|
| 79 |
)
|
| 80 |
|
| 81 |
|
| 82 |
+
def bit_linear(
|
| 83 |
+
x: torch.Tensor,
|
| 84 |
+
weight: torch.Tensor,
|
| 85 |
+
bias: torch.Tensor | None = None,
|
| 86 |
+
norm_weight: torch.Tensor | None = None,
|
| 87 |
+
norm_bias: torch.Tensor | None = None,
|
| 88 |
+
eps: float = 1e-8,
|
| 89 |
+
) -> torch.Tensor:
|
| 90 |
+
"""Apply RMS normalization and a linear projection with quantized activations and weights."""
|
| 91 |
+
return layer_norm_linear_quant(
|
| 92 |
+
x=x,
|
| 93 |
+
norm_weight=norm_weight,
|
| 94 |
+
norm_bias=norm_bias,
|
| 95 |
+
linear_weight=weight,
|
| 96 |
+
linear_bias=bias,
|
| 97 |
+
eps=eps,
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 98 |
is_rms_norm=True,
|
| 99 |
)
|
| 100 |
|
| 101 |
|
| 102 |
class BitLinear(nn.Linear):
|
| 103 |
"""
|
| 104 |
+
RMS-normalized linear layer with 8-bit activations and ternary weights.
|
| 105 |
+
|
| 106 |
+
Quantization uses a straight-through estimator during training.
|
| 107 |
+
Efficient deployment requires specialized kernels.
|
| 108 |
|
| 109 |
+
Args:
|
| 110 |
+
in_features (int):
|
| 111 |
+
Size of each input sample.
|
| 112 |
+
out_features (int):
|
| 113 |
+
Size of each output sample.
|
| 114 |
+
bias (bool, Optional):
|
| 115 |
+
Whether to allocate an additive bias. Default: `False`.
|
| 116 |
+
norm_eps (float, Optional):
|
| 117 |
+
Epsilon for RMS normalization. Default: 1e-8.
|
| 118 |
+
"""
|
| 119 |
|
| 120 |
+
def __init__(self, in_features: int, out_features: int, bias: bool = False, norm_eps: float = 1e-8) -> None:
|
| 121 |
+
super().__init__(in_features=in_features, out_features=out_features, bias=bias)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 122 |
|
| 123 |
+
self.norm = RMSNorm(hidden_size=in_features, eps=norm_eps, dtype=torch.float32)
|
| 124 |
|
| 125 |
def __repr__(self) -> str:
|
| 126 |
return f"{self.__class__.__name__}({super().extra_repr()}, norm_eps={self.norm.eps})"
|
| 127 |
|
| 128 |
+
def forward(self, x: torch.Tensor) -> torch.Tensor:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 129 |
w = self.weight
|
| 130 |
+
x_norm = self.norm(x=x)
|
| 131 |
|
| 132 |
+
# straight-through gradients bypass quantization
|
| 133 |
+
x_quant = x_norm + (activation_quant(x=x_norm) - x_norm).detach()
|
| 134 |
+
w_quant = w + (weight_quant(w=w) - w).detach()
|
| 135 |
+
y = F.linear(input=x_quant, weight=w_quant)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 136 |
|
| 137 |
return y
|
| 138 |
|
| 139 |
|
| 140 |
class FusedBitLinear(BitLinear):
|
| 141 |
+
"""BitLinear with fused RMS normalization and activation quantization."""
|
| 142 |
+
|
| 143 |
+
def __init__(self, in_features: int, out_features: int, bias: bool = False) -> None:
|
| 144 |
+
super().__init__(in_features=in_features, out_features=out_features, bias=bias)
|
| 145 |
+
|
| 146 |
+
def forward(self, x: torch.Tensor) -> torch.Tensor:
|
| 147 |
+
return layer_norm_linear_quant(
|
| 148 |
+
x=x,
|
| 149 |
+
norm_weight=self.norm.weight,
|
| 150 |
+
norm_bias=self.norm.bias,
|
| 151 |
+
linear_weight=self.weight,
|
| 152 |
+
linear_bias=self.bias,
|
| 153 |
+
eps=self.norm.eps,
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 154 |
is_rms_norm=True,
|
| 155 |
)
|
build/torch-cuda/modules/fused_cross_entropy.py
DELETED
|
@@ -1,459 +0,0 @@
|
|
| 1 |
-
# Copyright (c) 2023-2026, Songlin Yang, Yu Zhang, Zhiyuan Li
|
| 2 |
-
#
|
| 3 |
-
# This source code is licensed under the MIT license found in the
|
| 4 |
-
# LICENSE file in the root directory of this source tree.
|
| 5 |
-
# For a list of all contributors, visit:
|
| 6 |
-
# https://github.com/fla-org/flash-linear-attention/graphs/contributors
|
| 7 |
-
|
| 8 |
-
from typing import Any
|
| 9 |
-
|
| 10 |
-
import torch
|
| 11 |
-
import torch.nn as nn
|
| 12 |
-
import triton
|
| 13 |
-
import triton.language as tl
|
| 14 |
-
|
| 15 |
-
from ..modules.backends import dispatch
|
| 16 |
-
from ..ops.utils.op import exp, log, tanh
|
| 17 |
-
from ..utils import input_guard
|
| 18 |
-
|
| 19 |
-
# `all_gather_into_tensor` and `reduce_scatter_tensor` are new placeholders for
|
| 20 |
-
# `_all_gather_base` and `_reduce_scatter_base`. They require the most recent
|
| 21 |
-
# version of PyTorch. The following 2 lines are for backward compatibility with
|
| 22 |
-
# older PyTorch.
|
| 23 |
-
if "all_gather_into_tensor" not in dir(torch.distributed):
|
| 24 |
-
torch.distributed.all_gather_into_tensor = torch.distributed._all_gather_base
|
| 25 |
-
|
| 26 |
-
|
| 27 |
-
@triton.heuristics({
|
| 28 |
-
"HAS_SMOOTHING": lambda args: args["label_smoothing"] > 0.0,
|
| 29 |
-
"HAS_SOFTCAPPING": lambda args: args["logit_softcapping"] is not None,
|
| 30 |
-
})
|
| 31 |
-
@triton.jit
|
| 32 |
-
def cross_entropy_fwd_kernel(
|
| 33 |
-
loss_ptr, # data ptrs
|
| 34 |
-
lse_ptr,
|
| 35 |
-
z_loss_ptr,
|
| 36 |
-
logits_ptr,
|
| 37 |
-
labels_ptr,
|
| 38 |
-
label_smoothing,
|
| 39 |
-
logit_scale,
|
| 40 |
-
lse_square_scale,
|
| 41 |
-
logit_softcapping,
|
| 42 |
-
ignore_index,
|
| 43 |
-
total_classes,
|
| 44 |
-
class_start_idx, # Useful for tensor parallel when each rank only has a subset of classes
|
| 45 |
-
n_cols, # shapes
|
| 46 |
-
n_rows,
|
| 47 |
-
logits_row_stride, # strides
|
| 48 |
-
BLOCK_SIZE: tl.constexpr,
|
| 49 |
-
HAS_SMOOTHING: tl.constexpr,
|
| 50 |
-
HAS_SOFTCAPPING: tl.constexpr,
|
| 51 |
-
# if SPLIT (e.g. tensor parallel), don't include the LSE in the loss since it's not the final LSE
|
| 52 |
-
SPLIT: tl.constexpr,
|
| 53 |
-
):
|
| 54 |
-
row_idx = tl.program_id(0)
|
| 55 |
-
col_block_idx = tl.program_id(1)
|
| 56 |
-
logits_ptr = logits_ptr + row_idx * logits_row_stride.to(tl.int64)
|
| 57 |
-
col_offsets = col_block_idx * BLOCK_SIZE + tl.arange(0, BLOCK_SIZE)
|
| 58 |
-
label_idx = tl.load(labels_ptr + row_idx)
|
| 59 |
-
logits = tl.load(logits_ptr + col_offsets, mask=col_offsets < n_cols, other=-float("inf"))
|
| 60 |
-
logits = logits.to(tl.float32) * logit_scale
|
| 61 |
-
if HAS_SOFTCAPPING:
|
| 62 |
-
logits = logit_softcapping * tanh(logits / logit_softcapping)
|
| 63 |
-
max_logits = tl.max(logits, 0)
|
| 64 |
-
if HAS_SMOOTHING:
|
| 65 |
-
sum_logits = tl.sum(tl.where(col_offsets < n_cols, logits, 0.0), 0)
|
| 66 |
-
lse = log(tl.sum(exp(logits - max_logits), 0)) + max_logits
|
| 67 |
-
tl.store(lse_ptr + col_block_idx * n_rows + row_idx, lse)
|
| 68 |
-
if label_idx == ignore_index:
|
| 69 |
-
loss = 0.0
|
| 70 |
-
z_loss = 0.0
|
| 71 |
-
else:
|
| 72 |
-
label_idx -= class_start_idx
|
| 73 |
-
if label_idx >= col_block_idx * BLOCK_SIZE and label_idx < min(
|
| 74 |
-
n_cols, (col_block_idx + 1) * BLOCK_SIZE,
|
| 75 |
-
):
|
| 76 |
-
logits_label = tl.load(logits_ptr + label_idx).to(tl.float32) * logit_scale
|
| 77 |
-
if HAS_SOFTCAPPING:
|
| 78 |
-
logits_label = logit_softcapping * tanh(logits_label / logit_softcapping)
|
| 79 |
-
if HAS_SMOOTHING:
|
| 80 |
-
loss = (
|
| 81 |
-
(lse if not SPLIT else 0.0)
|
| 82 |
-
- label_smoothing * sum_logits / total_classes
|
| 83 |
-
- (1 - label_smoothing) * logits_label
|
| 84 |
-
)
|
| 85 |
-
else:
|
| 86 |
-
loss = (lse if not SPLIT else 0.0) - logits_label
|
| 87 |
-
else:
|
| 88 |
-
# If label is out of bounds, we set the CE loss to 0.0. But we still want the label_smoothing loss
|
| 89 |
-
if HAS_SMOOTHING:
|
| 90 |
-
loss = label_smoothing * ((lse if not SPLIT else 0.0) - sum_logits / total_classes)
|
| 91 |
-
else:
|
| 92 |
-
loss = 0.0
|
| 93 |
-
if not SPLIT:
|
| 94 |
-
z_loss = lse_square_scale * lse * lse
|
| 95 |
-
loss += z_loss
|
| 96 |
-
else:
|
| 97 |
-
z_loss = 0.0
|
| 98 |
-
tl.store(loss_ptr + col_block_idx * n_rows + row_idx, loss)
|
| 99 |
-
if not SPLIT:
|
| 100 |
-
tl.store(z_loss_ptr + col_block_idx * n_rows + row_idx, z_loss)
|
| 101 |
-
|
| 102 |
-
|
| 103 |
-
@triton.heuristics({
|
| 104 |
-
"HAS_SMOOTHING": lambda args: args["label_smoothing"] > 0.0,
|
| 105 |
-
"HAS_SOFTCAPPING": lambda args: args["logit_softcapping"] is not None,
|
| 106 |
-
})
|
| 107 |
-
@triton.jit
|
| 108 |
-
def cross_entropy_bwd_kernel(
|
| 109 |
-
dlogits_ptr, # data ptrs
|
| 110 |
-
dloss_ptr,
|
| 111 |
-
logits_ptr,
|
| 112 |
-
lse_ptr,
|
| 113 |
-
labels_ptr,
|
| 114 |
-
label_smoothing,
|
| 115 |
-
logit_scale,
|
| 116 |
-
lse_square_scale,
|
| 117 |
-
logit_softcapping,
|
| 118 |
-
ignore_index,
|
| 119 |
-
total_classes,
|
| 120 |
-
class_start_idx, # Useful for tensor parallel when each rank only has a subset of classes
|
| 121 |
-
n_cols, # shapes
|
| 122 |
-
logits_row_stride, # strides
|
| 123 |
-
dlogits_row_stride,
|
| 124 |
-
dloss_row_stride,
|
| 125 |
-
BLOCK_SIZE: tl.constexpr,
|
| 126 |
-
HAS_SMOOTHING: tl.constexpr,
|
| 127 |
-
HAS_SOFTCAPPING: tl.constexpr,
|
| 128 |
-
):
|
| 129 |
-
row_idx = tl.program_id(0)
|
| 130 |
-
col_block_idx = tl.program_id(1)
|
| 131 |
-
logits_ptr = logits_ptr + row_idx * logits_row_stride.to(tl.int64)
|
| 132 |
-
dlogits_ptr = dlogits_ptr + row_idx * dlogits_row_stride.to(tl.int64)
|
| 133 |
-
col_offsets = col_block_idx * BLOCK_SIZE + tl.arange(0, BLOCK_SIZE)
|
| 134 |
-
label_idx = tl.load(labels_ptr + row_idx)
|
| 135 |
-
if label_idx != ignore_index:
|
| 136 |
-
dloss = tl.load(dloss_ptr + row_idx * dloss_row_stride)
|
| 137 |
-
else:
|
| 138 |
-
dloss = 0.0
|
| 139 |
-
logits = tl.load(logits_ptr + col_offsets, mask=col_offsets < n_cols, other=-float("inf")).to(
|
| 140 |
-
tl.float32,
|
| 141 |
-
) * logit_scale
|
| 142 |
-
if HAS_SOFTCAPPING:
|
| 143 |
-
t = tanh(logits / logit_softcapping)
|
| 144 |
-
logits = logit_softcapping * t
|
| 145 |
-
lse = tl.load(lse_ptr + row_idx)
|
| 146 |
-
probs = exp(logits - lse)
|
| 147 |
-
probs += 2.0 * lse_square_scale * lse * probs
|
| 148 |
-
label_idx -= class_start_idx
|
| 149 |
-
if HAS_SMOOTHING:
|
| 150 |
-
smooth_negative = label_smoothing / total_classes
|
| 151 |
-
probs = tl.where(col_offsets == label_idx, probs - (1 - label_smoothing), probs) - smooth_negative
|
| 152 |
-
else:
|
| 153 |
-
probs = tl.where(col_offsets == label_idx, probs - 1.0, probs)
|
| 154 |
-
# d(softcap * tanh(x/softcap))/dx = 1 - tanh(x/softcap)^2
|
| 155 |
-
if HAS_SOFTCAPPING:
|
| 156 |
-
probs = probs * (1.0 - t * t)
|
| 157 |
-
tl.store(dlogits_ptr + col_offsets, (dloss * logit_scale) * probs, mask=col_offsets < n_cols)
|
| 158 |
-
|
| 159 |
-
|
| 160 |
-
def fused_cross_entropy_forward(
|
| 161 |
-
logits: torch.Tensor,
|
| 162 |
-
target: torch.Tensor,
|
| 163 |
-
label_smoothing: float = 0.0,
|
| 164 |
-
logit_scale: float = 1.0,
|
| 165 |
-
lse_square_scale: float = 0.0,
|
| 166 |
-
logit_softcapping: float = None,
|
| 167 |
-
ignore_index: int = -100,
|
| 168 |
-
process_group=None,
|
| 169 |
-
):
|
| 170 |
-
n_rows, n_cols = logits.shape
|
| 171 |
-
assert target.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 |
-
|
| 177 |
-
if logits.stride(-1) != 1:
|
| 178 |
-
logits = logits.contiguous()
|
| 179 |
-
# Set these similar to https://github.com/triton-lang/triton/blob/main/python/tutorials/02-fused-softmax.py
|
| 180 |
-
MAX_BLOCK_SIZE = 64 * 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 |
-
# We may split the lse computation across multiple blocks, then do a reduction
|
| 188 |
-
# lse(local_lse) to get the final LSE. This is faster for large n_cols (e.g., > 64k)
|
| 189 |
-
# where having just one thread block processing more than 64k elements is slow.
|
| 190 |
-
split = world_size > 1 or n_cols > MAX_BLOCK_SIZE
|
| 191 |
-
n_splits = (n_cols + BLOCK_SIZE - 1) // BLOCK_SIZE
|
| 192 |
-
loss_shape = (n_splits, n_rows) if n_splits > 1 else (n_rows,)
|
| 193 |
-
losses = torch.empty(*loss_shape, dtype=torch.float, device=logits.device)
|
| 194 |
-
lse = torch.empty(*loss_shape, dtype=torch.float, device=logits.device)
|
| 195 |
-
z_losses = torch.empty(*loss_shape, dtype=torch.float, device=logits.device)
|
| 196 |
-
|
| 197 |
-
cross_entropy_fwd_kernel[(n_rows, n_splits)](
|
| 198 |
-
losses, # data ptrs
|
| 199 |
-
lse,
|
| 200 |
-
z_losses,
|
| 201 |
-
logits,
|
| 202 |
-
target,
|
| 203 |
-
label_smoothing,
|
| 204 |
-
logit_scale,
|
| 205 |
-
lse_square_scale,
|
| 206 |
-
logit_softcapping,
|
| 207 |
-
ignore_index,
|
| 208 |
-
total_classes,
|
| 209 |
-
class_start_idx,
|
| 210 |
-
n_cols, # shapes
|
| 211 |
-
n_rows,
|
| 212 |
-
logits.stride(0), # strides
|
| 213 |
-
BLOCK_SIZE=BLOCK_SIZE, # constants
|
| 214 |
-
num_warps=num_warps,
|
| 215 |
-
SPLIT=split,
|
| 216 |
-
)
|
| 217 |
-
|
| 218 |
-
if split:
|
| 219 |
-
# If there's no label_smoothing, if target are in the vocab of this partition, losses contains
|
| 220 |
-
# - predicted logit, and 0 otherwise.
|
| 221 |
-
# If there's label_smoothing=0.1, for target in the vocab of this partition, losses contains
|
| 222 |
-
# -0.9 * predicted logit - 0.1 * sum logit / total_classes.
|
| 223 |
-
# For target not in the vocab of this partition, losses contains
|
| 224 |
-
# -0.1 * sum logit / total_classes.
|
| 225 |
-
if n_splits > 1:
|
| 226 |
-
lse = torch.logsumexp(lse, dim=0)
|
| 227 |
-
losses = losses.sum(dim=0)
|
| 228 |
-
if world_size > 1:
|
| 229 |
-
lse_allgather = torch.empty(world_size, n_rows, dtype=lse.dtype, device=lse.device)
|
| 230 |
-
torch.distributed.all_gather_into_tensor(lse_allgather, lse, group=process_group)
|
| 231 |
-
handle_losses = torch.distributed.all_reduce(
|
| 232 |
-
losses, op=torch.distributed.ReduceOp.SUM, group=process_group, async_op=True,
|
| 233 |
-
)
|
| 234 |
-
lse = torch.logsumexp(lse_allgather, dim=0)
|
| 235 |
-
handle_losses.wait()
|
| 236 |
-
# After the allreduce, if there's no label_smoothing, the total losses are - predicted_logit,
|
| 237 |
-
# we just have to add the (global) lse.
|
| 238 |
-
# If there's label_smoothing=0.1, the total losses are
|
| 239 |
-
# -0.9 * predicted_logit - 0.1 * sum logit / total_classes.
|
| 240 |
-
# Again, we just have to add the (global) lse.
|
| 241 |
-
losses += lse
|
| 242 |
-
if lse_square_scale != 0.0:
|
| 243 |
-
z_losses = lse_square_scale * lse.square()
|
| 244 |
-
z_losses.masked_fill_(target == ignore_index, 0.0)
|
| 245 |
-
losses += z_losses
|
| 246 |
-
else:
|
| 247 |
-
z_losses = torch.zeros_like(losses)
|
| 248 |
-
losses.masked_fill_(target == ignore_index, 0.0)
|
| 249 |
-
|
| 250 |
-
return losses, z_losses, lse, total_classes, class_start_idx
|
| 251 |
-
|
| 252 |
-
|
| 253 |
-
class CrossEntropyLossFunction(torch.autograd.Function):
|
| 254 |
-
|
| 255 |
-
@staticmethod
|
| 256 |
-
@input_guard
|
| 257 |
-
def forward(
|
| 258 |
-
ctx,
|
| 259 |
-
logits,
|
| 260 |
-
target,
|
| 261 |
-
label_smoothing=0.0,
|
| 262 |
-
logit_scale=1.0,
|
| 263 |
-
lse_square_scale=0.0,
|
| 264 |
-
logit_softcapping=None,
|
| 265 |
-
ignore_index=-100,
|
| 266 |
-
inplace_backward=False,
|
| 267 |
-
process_group=None,
|
| 268 |
-
):
|
| 269 |
-
losses, z_losses, lse, total_classes, class_start_idx = fused_cross_entropy_forward(
|
| 270 |
-
logits,
|
| 271 |
-
target,
|
| 272 |
-
label_smoothing,
|
| 273 |
-
logit_scale,
|
| 274 |
-
lse_square_scale,
|
| 275 |
-
logit_softcapping,
|
| 276 |
-
ignore_index,
|
| 277 |
-
process_group,
|
| 278 |
-
)
|
| 279 |
-
ctx.save_for_backward(logits, lse, target)
|
| 280 |
-
ctx.mark_non_differentiable(z_losses)
|
| 281 |
-
ctx.label_smoothing = label_smoothing
|
| 282 |
-
ctx.logit_scale = logit_scale
|
| 283 |
-
ctx.lse_square_scale = lse_square_scale
|
| 284 |
-
ctx.logit_softcapping = logit_softcapping
|
| 285 |
-
ctx.ignore_index = ignore_index
|
| 286 |
-
ctx.total_classes = total_classes
|
| 287 |
-
ctx.class_start_idx = class_start_idx
|
| 288 |
-
ctx.inplace_backward = inplace_backward
|
| 289 |
-
|
| 290 |
-
return losses, z_losses
|
| 291 |
-
|
| 292 |
-
@staticmethod
|
| 293 |
-
@input_guard
|
| 294 |
-
def backward(ctx, grad_losses, grad_z_losses):
|
| 295 |
-
del grad_z_losses # z_losses are only for logging.
|
| 296 |
-
|
| 297 |
-
logits, lse, target = ctx.saved_tensors
|
| 298 |
-
dlogits = logits if ctx.inplace_backward else torch.empty_like(logits)
|
| 299 |
-
n_rows, n_cols = logits.shape
|
| 300 |
-
BLOCK_SIZE = min(triton.next_power_of_2(n_cols), 4 * 1024)
|
| 301 |
-
num_warps = 4 if BLOCK_SIZE < 2048 else (8 if BLOCK_SIZE < 8192 else 16)
|
| 302 |
-
def grid(META): return (n_rows, triton.cdiv(n_cols, META["BLOCK_SIZE"])) # noqa
|
| 303 |
-
cross_entropy_bwd_kernel[grid](
|
| 304 |
-
dlogits, # data ptrs
|
| 305 |
-
grad_losses,
|
| 306 |
-
logits,
|
| 307 |
-
lse,
|
| 308 |
-
target,
|
| 309 |
-
ctx.label_smoothing,
|
| 310 |
-
ctx.logit_scale,
|
| 311 |
-
ctx.lse_square_scale,
|
| 312 |
-
ctx.logit_softcapping,
|
| 313 |
-
ctx.ignore_index,
|
| 314 |
-
ctx.total_classes,
|
| 315 |
-
ctx.class_start_idx,
|
| 316 |
-
n_cols, # shapes
|
| 317 |
-
logits.stride(0), # strides
|
| 318 |
-
dlogits.stride(0),
|
| 319 |
-
grad_losses.stride(0),
|
| 320 |
-
BLOCK_SIZE=BLOCK_SIZE, # constants
|
| 321 |
-
num_warps=num_warps,
|
| 322 |
-
)
|
| 323 |
-
return dlogits, None, None, None, None, None, None, None, None, None
|
| 324 |
-
|
| 325 |
-
|
| 326 |
-
@dispatch('modules')
|
| 327 |
-
def cross_entropy_loss(
|
| 328 |
-
logits: torch.Tensor,
|
| 329 |
-
target: torch.Tensor,
|
| 330 |
-
label_smoothing: float = 0.0,
|
| 331 |
-
logit_scale: float = 1.0,
|
| 332 |
-
lse_square_scale: float = 0.0,
|
| 333 |
-
logit_softcapping: float = None,
|
| 334 |
-
ignore_index=-100,
|
| 335 |
-
inplace_backward: bool = False,
|
| 336 |
-
process_group=None,
|
| 337 |
-
) -> tuple[torch.Tensor, torch.Tensor]:
|
| 338 |
-
"""
|
| 339 |
-
Arguments:
|
| 340 |
-
logits: [batch, vocab_size]
|
| 341 |
-
target: [batch,]
|
| 342 |
-
label_smoothing: float
|
| 343 |
-
logit_scale: float.
|
| 344 |
-
Multiply logits by this scale before calculating the loss.
|
| 345 |
-
lse_square_scale: float.
|
| 346 |
-
If > 0, we add lse_square_scale * lse(logits) ^ 2 to the loss.
|
| 347 |
-
This is also referred to as "z-loss".
|
| 348 |
-
logit_softcapping: float.
|
| 349 |
-
If > 0, apply logit softcapping: logits = softcap * tanh(logits / softcap).
|
| 350 |
-
This prevents logit magnitudes from growing unboundedly.
|
| 351 |
-
ignore_index: int.
|
| 352 |
-
If target == ignore_index, the loss is set to 0.0.
|
| 353 |
-
inplace_backward: bool.
|
| 354 |
-
If True, we do the backward pass in-place by modifying the logits.
|
| 355 |
-
This saves memory.
|
| 356 |
-
process_group:
|
| 357 |
-
if not None, we're doing Tensor Parallel: each process is responsible for
|
| 358 |
-
one part of the vocab. The loss will be aggregated across processes.
|
| 359 |
-
Returns:
|
| 360 |
-
losses: [batch,], float
|
| 361 |
-
z_losses: [batch,], float
|
| 362 |
-
"""
|
| 363 |
-
return CrossEntropyLossFunction.apply(
|
| 364 |
-
logits,
|
| 365 |
-
target,
|
| 366 |
-
label_smoothing,
|
| 367 |
-
logit_scale,
|
| 368 |
-
lse_square_scale,
|
| 369 |
-
logit_softcapping,
|
| 370 |
-
ignore_index,
|
| 371 |
-
inplace_backward,
|
| 372 |
-
process_group,
|
| 373 |
-
)
|
| 374 |
-
|
| 375 |
-
|
| 376 |
-
class FusedCrossEntropyLoss(nn.Module):
|
| 377 |
-
def __init__(
|
| 378 |
-
self,
|
| 379 |
-
ignore_index: int = -100,
|
| 380 |
-
reduction: str = "mean",
|
| 381 |
-
label_smoothing: float = 0.0,
|
| 382 |
-
logit_scale: float = 1.0,
|
| 383 |
-
lse_square_scale: float = 0.0,
|
| 384 |
-
logit_softcapping: float = None,
|
| 385 |
-
inplace_backward: bool = False,
|
| 386 |
-
process_group: Any = None,
|
| 387 |
-
return_z_loss: bool = False,
|
| 388 |
-
):
|
| 389 |
-
"""
|
| 390 |
-
Arguments:
|
| 391 |
-
ignore_index: int. If target == ignore_index, the loss is set to 0.0.
|
| 392 |
-
label_smoothing: float
|
| 393 |
-
lse_square_scale: float. If > 0, we add lse_square_scale * lse(logits) ^ 2 to the loss.
|
| 394 |
-
This is also referred to as "z-loss".
|
| 395 |
-
logit_softcapping: float. If > 0, apply logit softcapping:
|
| 396 |
-
logits = softcap * tanh(logits / softcap).
|
| 397 |
-
This prevents logit magnitudes from growing unboundedly.
|
| 398 |
-
inplace_backward: bool. If True, we do the backward pass in-place by modifying the logits.
|
| 399 |
-
This saves memory.
|
| 400 |
-
process_group: if not None, we're doing Tensor Parallel: each process is responsible for
|
| 401 |
-
one part of the vocab. The loss will be aggregated across processes.
|
| 402 |
-
return_z_loss: bool. If True, we return the component of the loss contributed by
|
| 403 |
-
the lse_square_scale value. This value is only for logging and does not support
|
| 404 |
-
backprop.
|
| 405 |
-
"""
|
| 406 |
-
super().__init__()
|
| 407 |
-
if reduction not in ["mean", "none", "sum"]:
|
| 408 |
-
raise NotImplementedError("Only support reduction = 'mean' or 'none' or 'sum'")
|
| 409 |
-
self.ignore_index = ignore_index
|
| 410 |
-
self.reduction = reduction
|
| 411 |
-
self.label_smoothing = label_smoothing
|
| 412 |
-
self.logit_scale = logit_scale
|
| 413 |
-
self.lse_square_scale = lse_square_scale
|
| 414 |
-
self.logit_softcapping = logit_softcapping
|
| 415 |
-
self.inplace_backward = inplace_backward
|
| 416 |
-
self.process_group = process_group
|
| 417 |
-
self.return_z_loss = return_z_loss
|
| 418 |
-
|
| 419 |
-
def forward(self, input, target):
|
| 420 |
-
"""
|
| 421 |
-
Arguments:
|
| 422 |
-
input: (batch, vocab_size)
|
| 423 |
-
target: (batch,)
|
| 424 |
-
Returns:
|
| 425 |
-
losses: (batch,) if reduction is 'none', else (1,), dtype float
|
| 426 |
-
z_loss: (batch,) if reduction is 'none', else (1,), dtype float (if self.return_z_loss)
|
| 427 |
-
"""
|
| 428 |
-
assert input.device.type in ('cuda', 'npu') and target.device.type in ('cuda', 'npu'), (
|
| 429 |
-
"Only support CUDA/NPU tensors"
|
| 430 |
-
)
|
| 431 |
-
loss, z_loss = cross_entropy_loss(
|
| 432 |
-
input,
|
| 433 |
-
target,
|
| 434 |
-
label_smoothing=self.label_smoothing,
|
| 435 |
-
logit_scale=self.logit_scale,
|
| 436 |
-
lse_square_scale=self.lse_square_scale,
|
| 437 |
-
logit_softcapping=self.logit_softcapping,
|
| 438 |
-
ignore_index=self.ignore_index,
|
| 439 |
-
inplace_backward=self.inplace_backward,
|
| 440 |
-
process_group=self.process_group,
|
| 441 |
-
)
|
| 442 |
-
if self.reduction == "mean":
|
| 443 |
-
loss = loss.sum() / (target != self.ignore_index).sum()
|
| 444 |
-
elif self.reduction == "sum":
|
| 445 |
-
loss = loss.sum()
|
| 446 |
-
else:
|
| 447 |
-
loss = loss
|
| 448 |
-
|
| 449 |
-
if not self.return_z_loss:
|
| 450 |
-
return loss
|
| 451 |
-
|
| 452 |
-
if self.reduction == "mean":
|
| 453 |
-
z_loss = z_loss.sum() / (target != self.ignore_index).sum()
|
| 454 |
-
elif self.reduction == "sum":
|
| 455 |
-
z_loss = z_loss.sum()
|
| 456 |
-
else:
|
| 457 |
-
z_loss = z_loss
|
| 458 |
-
|
| 459 |
-
return loss, z_loss
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
build/torch-cuda/modules/fused_cross_entropy/__init__.py
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright (c) 2023-2026, Songlin Yang, Yu Zhang, Zhiyuan Li
|
| 2 |
+
#
|
| 3 |
+
# This source code is licensed under the MIT license found in the
|
| 4 |
+
# LICENSE file in the root directory of this source tree.
|
| 5 |
+
# For a list of all contributors, visit:
|
| 6 |
+
# https://github.com/fla-org/flash-linear-attention/graphs/contributors
|
| 7 |
+
|
| 8 |
+
from ...backends import GluonBackend
|
| 9 |
+
from ...modules.fused_cross_entropy.ops import FusedCrossEntropyLoss, cross_entropy_loss
|
| 10 |
+
|
| 11 |
+
__all__ = ['FusedCrossEntropyLoss', 'cross_entropy_loss']
|
| 12 |
+
|
| 13 |
+
|
| 14 |
+
if GluonBackend.is_available():
|
| 15 |
+
from ...modules.fused_cross_entropy import gluon # noqa: F401
|
build/torch-cuda/modules/fused_cross_entropy/gluon.py
ADDED
|
@@ -0,0 +1,402 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright (c) 2023-2026, Songlin Yang, Yu Zhang, Zhiyuan Li
|
| 2 |
+
#
|
| 3 |
+
# This source code is licensed under the MIT license found in the
|
| 4 |
+
# LICENSE file in the root directory of this source tree.
|
| 5 |
+
# For a list of all contributors, visit:
|
| 6 |
+
# https://github.com/fla-org/flash-linear-attention/graphs/contributors
|
| 7 |
+
|
| 8 |
+
from __future__ import annotations
|
| 9 |
+
|
| 10 |
+
import os
|
| 11 |
+
from typing import TYPE_CHECKING
|
| 12 |
+
|
| 13 |
+
import torch
|
| 14 |
+
import triton
|
| 15 |
+
from triton.experimental import gluon
|
| 16 |
+
from triton.experimental.gluon import language as gl
|
| 17 |
+
from triton.experimental.gluon.language import extra
|
| 18 |
+
|
| 19 |
+
from ...backends import GluonBackend, register
|
| 20 |
+
from ...modules.fused_cross_entropy.ops import cross_entropy_bwd, cross_entropy_fwd
|
| 21 |
+
|
| 22 |
+
if TYPE_CHECKING:
|
| 23 |
+
from torch.distributed import ProcessGroup
|
| 24 |
+
|
| 25 |
+
|
| 26 |
+
if os.environ.get('FLA_USE_FAST_OPS', '0') == '1':
|
| 27 |
+
exp = extra.libdevice.fast_expf
|
| 28 |
+
log = extra.libdevice.fast_logf
|
| 29 |
+
else:
|
| 30 |
+
exp = gl.exp
|
| 31 |
+
log = gl.log
|
| 32 |
+
tanh = extra.libdevice.tanh
|
| 33 |
+
|
| 34 |
+
|
| 35 |
+
@gluon.jit(do_not_specialize=['N'])
|
| 36 |
+
def cross_entropy_fwd_kernel_gluon(
|
| 37 |
+
logits, # [N, V]
|
| 38 |
+
target, # [N]
|
| 39 |
+
loss, # [NV, N] or [N] when NV == 1
|
| 40 |
+
z_loss, # [N]
|
| 41 |
+
lse, # [NV, N] or [N] when NV == 1
|
| 42 |
+
s_logits,
|
| 43 |
+
label_smoothing: gl.constexpr,
|
| 44 |
+
logit_scale: gl.constexpr,
|
| 45 |
+
lse_square_scale: gl.constexpr,
|
| 46 |
+
logit_softcapping: gl.constexpr,
|
| 47 |
+
ignore_index: gl.constexpr,
|
| 48 |
+
N,
|
| 49 |
+
V: gl.constexpr,
|
| 50 |
+
V_TOTAL: gl.constexpr,
|
| 51 |
+
V_START: gl.constexpr,
|
| 52 |
+
BV: gl.constexpr,
|
| 53 |
+
SPLIT: gl.constexpr,
|
| 54 |
+
):
|
| 55 |
+
NW: gl.constexpr = 4
|
| 56 |
+
R_MAX: gl.constexpr = 128 // logits.dtype.element_ty.primitive_bitwidth
|
| 57 |
+
R: gl.constexpr = (V & -V) if (V & -V) < R_MAX else R_MAX
|
| 58 |
+
layout: gl.constexpr = gl.BlockedLayout([R], [32], [NW], [0])
|
| 59 |
+
i_n = gl.program_id(0).to(gl.int64)
|
| 60 |
+
i_v = gl.program_id(1).to(gl.int64)
|
| 61 |
+
o_v = i_v * BV + gl.arange(0, BV, layout=layout).to(gl.int64)
|
| 62 |
+
m_v = o_v < V
|
| 63 |
+
p_logits = logits + i_n * s_logits
|
| 64 |
+
|
| 65 |
+
# [BV]
|
| 66 |
+
b_logits = gl.load(p_logits + o_v, mask=m_v, other=-float('inf')).to(gl.float32) * logit_scale
|
| 67 |
+
if logit_softcapping is not None:
|
| 68 |
+
b_logits = logit_softcapping * tanh(b_logits / logit_softcapping)
|
| 69 |
+
# these transforms do not preserve -inf in padded lanes
|
| 70 |
+
if logit_softcapping is not None or logit_scale <= 0:
|
| 71 |
+
b_logits = gl.where(m_v, b_logits, -float('inf'))
|
| 72 |
+
if label_smoothing > 0:
|
| 73 |
+
b_sum = gl.sum(gl.where(m_v, b_logits, 0.0), 0)
|
| 74 |
+
b_max = gl.max(b_logits, 0)
|
| 75 |
+
b_lse = log(gl.sum(exp(b_logits - b_max), 0)) + b_max
|
| 76 |
+
|
| 77 |
+
b_target = gl.load(target + i_n).to(gl.int64)
|
| 78 |
+
b_loss = 0.0
|
| 79 |
+
b_z_loss = 0.0
|
| 80 |
+
if b_target != ignore_index:
|
| 81 |
+
b_target -= V_START
|
| 82 |
+
m_target = (b_target >= i_v * BV) & (b_target < gl.minimum(V, (i_v + 1) * BV))
|
| 83 |
+
b_target_logit = gl.load(p_logits + b_target, mask=m_target, other=0).to(gl.float32) * logit_scale
|
| 84 |
+
if logit_softcapping is not None:
|
| 85 |
+
b_target_logit = logit_softcapping * tanh(b_target_logit / logit_softcapping)
|
| 86 |
+
b_loss = -b_target_logit
|
| 87 |
+
if label_smoothing > 0:
|
| 88 |
+
b_loss = (1 - label_smoothing) * b_loss - label_smoothing * b_sum / V_TOTAL
|
| 89 |
+
if not SPLIT:
|
| 90 |
+
b_z_loss = lse_square_scale * b_lse * b_lse
|
| 91 |
+
b_loss += b_lse + b_z_loss
|
| 92 |
+
|
| 93 |
+
gl.store(loss + i_v * N + i_n, b_loss)
|
| 94 |
+
gl.store(lse + i_v * N + i_n, b_lse)
|
| 95 |
+
if not SPLIT:
|
| 96 |
+
gl.store(z_loss + i_n, b_z_loss)
|
| 97 |
+
|
| 98 |
+
|
| 99 |
+
@gluon.jit
|
| 100 |
+
def cross_entropy_bwd_kernel_gluon(
|
| 101 |
+
logits, # [N, V]
|
| 102 |
+
target, # [N]
|
| 103 |
+
lse, # [N]
|
| 104 |
+
dloss, # [N]
|
| 105 |
+
dlogits, # [N, V]
|
| 106 |
+
s_logits,
|
| 107 |
+
s_dloss,
|
| 108 |
+
s_dlogits,
|
| 109 |
+
label_smoothing: gl.constexpr,
|
| 110 |
+
logit_scale: gl.constexpr,
|
| 111 |
+
lse_square_scale: gl.constexpr,
|
| 112 |
+
logit_softcapping: gl.constexpr,
|
| 113 |
+
ignore_index: gl.constexpr,
|
| 114 |
+
V: gl.constexpr,
|
| 115 |
+
V_TOTAL: gl.constexpr,
|
| 116 |
+
V_START: gl.constexpr,
|
| 117 |
+
BV: gl.constexpr,
|
| 118 |
+
):
|
| 119 |
+
NW: gl.constexpr = 4
|
| 120 |
+
R_MAX: gl.constexpr = 128 // logits.dtype.element_ty.primitive_bitwidth
|
| 121 |
+
R: gl.constexpr = (V & -V) if (V & -V) < R_MAX else R_MAX
|
| 122 |
+
layout: gl.constexpr = gl.BlockedLayout([R], [32], [NW], [0])
|
| 123 |
+
i_n = gl.program_id(0).to(gl.int64)
|
| 124 |
+
i_v = gl.program_id(1).to(gl.int64)
|
| 125 |
+
o_local = gl.arange(0, BV, layout=layout)
|
| 126 |
+
o_v = i_v * BV + o_local.to(gl.int64)
|
| 127 |
+
if R == R_MAX and V > BV:
|
| 128 |
+
m_v = o_local < gl.minimum(V - i_v * BV, BV).to(gl.int32)
|
| 129 |
+
else:
|
| 130 |
+
m_v = o_v < V
|
| 131 |
+
p_logits = logits + i_n * s_logits + o_v
|
| 132 |
+
p_dlogits = dlogits + i_n * s_dlogits + o_v
|
| 133 |
+
|
| 134 |
+
b_target = gl.load(target + i_n).to(gl.int64)
|
| 135 |
+
b_dloss = gl.load(dloss + i_n * s_dloss, mask=b_target != ignore_index, other=0).to(gl.float32)
|
| 136 |
+
# [BV]
|
| 137 |
+
b_logits = gl.load(p_logits, mask=m_v, other=0).to(gl.float32) * logit_scale
|
| 138 |
+
if logit_softcapping is not None:
|
| 139 |
+
b_tanh = tanh(b_logits / logit_softcapping)
|
| 140 |
+
b_logits = logit_softcapping * b_tanh
|
| 141 |
+
b_lse = gl.load(lse + i_n)
|
| 142 |
+
# [BV]
|
| 143 |
+
b_probs = exp(b_logits - b_lse)
|
| 144 |
+
b_dlogits = b_probs + 2.0 * lse_square_scale * b_lse * b_probs
|
| 145 |
+
TARGET_WEIGHT: gl.constexpr = 1 - label_smoothing if label_smoothing > 0 else 1.0
|
| 146 |
+
b_target -= V_START
|
| 147 |
+
if R == R_MAX and V > BV:
|
| 148 |
+
b_target -= i_v * BV
|
| 149 |
+
if (b_target >= 0) & (b_target < BV):
|
| 150 |
+
b_dlogits -= gl.where(o_local == b_target.to(gl.int32), TARGET_WEIGHT, 0.0)
|
| 151 |
+
else:
|
| 152 |
+
b_dlogits -= gl.where(o_v == b_target, TARGET_WEIGHT, 0.0)
|
| 153 |
+
if label_smoothing > 0:
|
| 154 |
+
b_dlogits -= label_smoothing / V_TOTAL
|
| 155 |
+
if logit_softcapping is not None:
|
| 156 |
+
b_dlogits *= 1.0 - b_tanh * b_tanh
|
| 157 |
+
b_dlogits *= b_dloss * logit_scale
|
| 158 |
+
gl.store(p_dlogits, b_dlogits, mask=m_v)
|
| 159 |
+
|
| 160 |
+
|
| 161 |
+
@gluon.jit(do_not_specialize=['N'])
|
| 162 |
+
def cross_entropy_fwd_kernel_reduce_gluon(
|
| 163 |
+
partial_loss,
|
| 164 |
+
partial_lse,
|
| 165 |
+
target,
|
| 166 |
+
loss,
|
| 167 |
+
z_loss,
|
| 168 |
+
lse,
|
| 169 |
+
lse_square_scale: gl.constexpr,
|
| 170 |
+
ignore_index: gl.constexpr,
|
| 171 |
+
N,
|
| 172 |
+
NV: gl.constexpr,
|
| 173 |
+
BN: gl.constexpr,
|
| 174 |
+
BS: gl.constexpr,
|
| 175 |
+
SPLIT: gl.constexpr,
|
| 176 |
+
REDUCE_LOSS: gl.constexpr,
|
| 177 |
+
):
|
| 178 |
+
# keep partition reductions within a warp to avoid shared memory
|
| 179 |
+
P: gl.constexpr = 128 // BN
|
| 180 |
+
layout: gl.constexpr = gl.BlockedLayout([1, 1], [P, 32 // P], [1, 4], [1, 0])
|
| 181 |
+
o_n = gl.program_id(0).to(gl.int64) * BN + gl.arange(0, BN, layout=gl.SliceLayout(0, layout))
|
| 182 |
+
o_s = gl.arange(0, BS, layout=gl.SliceLayout(1, layout)).to(gl.int64)
|
| 183 |
+
offsets = o_s[:, None] * N + o_n[None, :]
|
| 184 |
+
mask = (o_s[:, None] < NV) & (o_n[None, :] < N)
|
| 185 |
+
b_lse = gl.load(partial_lse + offsets, mask=mask, other=-float('inf')).to(gl.float32)
|
| 186 |
+
b_max = gl.max(b_lse, 0)
|
| 187 |
+
b_lse = b_max + log(gl.sum(exp(b_lse - b_max[None, :]), 0))
|
| 188 |
+
if REDUCE_LOSS:
|
| 189 |
+
b_loss = gl.sum(gl.load(partial_loss + offsets, mask=mask, other=0).to(gl.float32), 0)
|
| 190 |
+
else:
|
| 191 |
+
b_loss = gl.load(partial_loss + o_n, mask=o_n < N, other=0).to(gl.float32)
|
| 192 |
+
if not SPLIT:
|
| 193 |
+
valid = gl.load(target + o_n, mask=o_n < N, other=ignore_index) != ignore_index
|
| 194 |
+
b_z_loss = gl.where(valid, lse_square_scale * b_lse * b_lse, 0.)
|
| 195 |
+
b_loss = gl.where(valid, b_loss + b_lse + b_z_loss, 0.)
|
| 196 |
+
gl.store(z_loss + o_n, b_z_loss, mask=o_n < N)
|
| 197 |
+
gl.store(loss + o_n, b_loss, mask=o_n < N)
|
| 198 |
+
gl.store(lse + o_n, b_lse, mask=o_n < N)
|
| 199 |
+
|
| 200 |
+
|
| 201 |
+
def cross_entropy_reduce_gluon(
|
| 202 |
+
loss: torch.Tensor,
|
| 203 |
+
z_loss: torch.Tensor,
|
| 204 |
+
lse: torch.Tensor,
|
| 205 |
+
target: torch.Tensor,
|
| 206 |
+
lse_square_scale: float,
|
| 207 |
+
ignore_index: int,
|
| 208 |
+
process_group: ProcessGroup | None,
|
| 209 |
+
) -> tuple[torch.Tensor, torch.Tensor, torch.Tensor]:
|
| 210 |
+
N = target.shape[0]
|
| 211 |
+
world_size = 1 if process_group is None else torch.distributed.get_world_size(group=process_group)
|
| 212 |
+
if lse.ndim == 2:
|
| 213 |
+
NV = lse.shape[0]
|
| 214 |
+
BS = triton.next_power_of_2(NV)
|
| 215 |
+
BN = 128 // max(1, min(8, BS // 4, 16384 // triton.next_power_of_2(N)))
|
| 216 |
+
reduced_loss = loss.new_empty(N)
|
| 217 |
+
reduced_lse = torch.empty_like(reduced_loss)
|
| 218 |
+
cross_entropy_fwd_kernel_reduce_gluon[(triton.cdiv(N, BN),)](
|
| 219 |
+
partial_loss=loss,
|
| 220 |
+
partial_lse=lse,
|
| 221 |
+
target=target,
|
| 222 |
+
loss=reduced_loss,
|
| 223 |
+
z_loss=z_loss,
|
| 224 |
+
lse=reduced_lse,
|
| 225 |
+
lse_square_scale=lse_square_scale,
|
| 226 |
+
ignore_index=ignore_index,
|
| 227 |
+
N=N,
|
| 228 |
+
NV=NV,
|
| 229 |
+
BN=BN,
|
| 230 |
+
BS=BS,
|
| 231 |
+
SPLIT=world_size > 1,
|
| 232 |
+
REDUCE_LOSS=True,
|
| 233 |
+
num_warps=4,
|
| 234 |
+
)
|
| 235 |
+
loss, lse = reduced_loss, reduced_lse
|
| 236 |
+
if world_size > 1:
|
| 237 |
+
BS = triton.next_power_of_2(world_size)
|
| 238 |
+
BN = 128 // max(1, min(8, BS // 4, 16384 // triton.next_power_of_2(N)))
|
| 239 |
+
gathered_lse = lse.new_empty(world_size, N)
|
| 240 |
+
torch.distributed.all_gather_into_tensor(output_tensor=gathered_lse, input_tensor=lse, group=process_group)
|
| 241 |
+
torch.distributed.all_reduce(tensor=loss, group=process_group)
|
| 242 |
+
cross_entropy_fwd_kernel_reduce_gluon[(triton.cdiv(N, BN),)](
|
| 243 |
+
partial_loss=loss,
|
| 244 |
+
partial_lse=gathered_lse,
|
| 245 |
+
target=target,
|
| 246 |
+
loss=loss,
|
| 247 |
+
z_loss=z_loss,
|
| 248 |
+
lse=lse,
|
| 249 |
+
lse_square_scale=lse_square_scale,
|
| 250 |
+
ignore_index=ignore_index,
|
| 251 |
+
N=N,
|
| 252 |
+
NV=world_size,
|
| 253 |
+
BN=BN,
|
| 254 |
+
BS=BS,
|
| 255 |
+
SPLIT=False,
|
| 256 |
+
REDUCE_LOSS=False,
|
| 257 |
+
num_warps=4,
|
| 258 |
+
)
|
| 259 |
+
return loss, z_loss, lse
|
| 260 |
+
|
| 261 |
+
|
| 262 |
+
def cross_entropy_fwd_verifier(
|
| 263 |
+
logits: torch.Tensor,
|
| 264 |
+
target: torch.Tensor,
|
| 265 |
+
label_smoothing: float = 0.0,
|
| 266 |
+
logit_scale: float = 1.0,
|
| 267 |
+
lse_square_scale: float = 0.0,
|
| 268 |
+
logit_softcapping: float | None = None,
|
| 269 |
+
ignore_index: int = -100,
|
| 270 |
+
process_group: ProcessGroup | None = None,
|
| 271 |
+
) -> tuple[bool, str | None]:
|
| 272 |
+
if logits.device.type != 'cuda' or target.device != logits.device:
|
| 273 |
+
return False, "Logits and targets must be on the same CUDA device"
|
| 274 |
+
if logits.dtype not in (torch.float16, torch.bfloat16, torch.float32):
|
| 275 |
+
return False, "Gluon cross entropy supports fp16, bf16, and fp32 logits"
|
| 276 |
+
return True, None
|
| 277 |
+
|
| 278 |
+
|
| 279 |
+
@register(cross_entropy_fwd, backend=GluonBackend, verifier=cross_entropy_fwd_verifier, env_var='FLA_CE_GLUON')
|
| 280 |
+
def cross_entropy_fwd_gluon(
|
| 281 |
+
logits: torch.Tensor,
|
| 282 |
+
target: torch.Tensor,
|
| 283 |
+
label_smoothing: float = 0.0,
|
| 284 |
+
logit_scale: float = 1.0,
|
| 285 |
+
lse_square_scale: float = 0.0,
|
| 286 |
+
logit_softcapping: float | None = None,
|
| 287 |
+
ignore_index: int = -100,
|
| 288 |
+
process_group: ProcessGroup | None = None,
|
| 289 |
+
):
|
| 290 |
+
N, V = logits.shape
|
| 291 |
+
assert target.shape == (N,)
|
| 292 |
+
world_size = 1 if process_group is None else torch.distributed.get_world_size(group=process_group)
|
| 293 |
+
total_classes = world_size * V
|
| 294 |
+
rank = 0 if process_group is None else torch.distributed.get_rank(group=process_group)
|
| 295 |
+
class_start_idx = rank * V
|
| 296 |
+
|
| 297 |
+
if logits.stride(-1) != 1:
|
| 298 |
+
logits = logits.contiguous()
|
| 299 |
+
BV = triton.next_power_of_2(V)
|
| 300 |
+
if logit_softcapping is not None:
|
| 301 |
+
BV = min(BV, 2048)
|
| 302 |
+
elif V > 16384:
|
| 303 |
+
BV = 8192
|
| 304 |
+
# vocab partitions contribute partial loss until the global LSE is available
|
| 305 |
+
NV = triton.cdiv(V, BV)
|
| 306 |
+
split = world_size > 1 or NV > 1
|
| 307 |
+
shape = (NV, N) if NV > 1 else (N,)
|
| 308 |
+
loss = logits.new_empty(shape, dtype=torch.float)
|
| 309 |
+
lse = torch.empty_like(loss)
|
| 310 |
+
z_loss = logits.new_empty(N, dtype=torch.float)
|
| 311 |
+
|
| 312 |
+
cross_entropy_fwd_kernel_gluon[(N, NV)](
|
| 313 |
+
logits=logits,
|
| 314 |
+
target=target,
|
| 315 |
+
loss=loss,
|
| 316 |
+
z_loss=z_loss,
|
| 317 |
+
lse=lse,
|
| 318 |
+
s_logits=logits.stride(0),
|
| 319 |
+
label_smoothing=label_smoothing,
|
| 320 |
+
logit_scale=logit_scale,
|
| 321 |
+
lse_square_scale=lse_square_scale,
|
| 322 |
+
logit_softcapping=logit_softcapping,
|
| 323 |
+
ignore_index=ignore_index,
|
| 324 |
+
N=N,
|
| 325 |
+
V=V,
|
| 326 |
+
V_TOTAL=total_classes,
|
| 327 |
+
V_START=class_start_idx,
|
| 328 |
+
BV=BV,
|
| 329 |
+
SPLIT=split,
|
| 330 |
+
num_warps=4,
|
| 331 |
+
)
|
| 332 |
+
|
| 333 |
+
if split:
|
| 334 |
+
loss, z_loss, lse = cross_entropy_reduce_gluon(
|
| 335 |
+
loss=loss,
|
| 336 |
+
z_loss=z_loss,
|
| 337 |
+
lse=lse,
|
| 338 |
+
target=target,
|
| 339 |
+
lse_square_scale=lse_square_scale,
|
| 340 |
+
ignore_index=ignore_index,
|
| 341 |
+
process_group=process_group,
|
| 342 |
+
)
|
| 343 |
+
|
| 344 |
+
return loss, z_loss, lse, total_classes, class_start_idx
|
| 345 |
+
|
| 346 |
+
|
| 347 |
+
def cross_entropy_bwd_verifier(
|
| 348 |
+
logits: torch.Tensor,
|
| 349 |
+
target: torch.Tensor,
|
| 350 |
+
lse: torch.Tensor,
|
| 351 |
+
dloss: torch.Tensor,
|
| 352 |
+
label_smoothing: float = 0.0,
|
| 353 |
+
logit_scale: float = 1.0,
|
| 354 |
+
lse_square_scale: float = 0.0,
|
| 355 |
+
logit_softcapping: float | None = None,
|
| 356 |
+
ignore_index: int = -100,
|
| 357 |
+
total_classes: int | None = None,
|
| 358 |
+
class_start_idx: int = 0,
|
| 359 |
+
inplace_backward: bool = False,
|
| 360 |
+
) -> tuple[bool, str | None]:
|
| 361 |
+
return cross_entropy_fwd_verifier(logits=logits, target=target)
|
| 362 |
+
|
| 363 |
+
|
| 364 |
+
@register(cross_entropy_bwd, backend=GluonBackend, verifier=cross_entropy_bwd_verifier, env_var='FLA_CE_GLUON')
|
| 365 |
+
def cross_entropy_bwd_gluon(
|
| 366 |
+
logits: torch.Tensor,
|
| 367 |
+
target: torch.Tensor,
|
| 368 |
+
lse: torch.Tensor,
|
| 369 |
+
dloss: torch.Tensor,
|
| 370 |
+
label_smoothing: float = 0.0,
|
| 371 |
+
logit_scale: float = 1.0,
|
| 372 |
+
lse_square_scale: float = 0.0,
|
| 373 |
+
logit_softcapping: float | None = None,
|
| 374 |
+
ignore_index: int = -100,
|
| 375 |
+
total_classes: int | None = None,
|
| 376 |
+
class_start_idx: int = 0,
|
| 377 |
+
inplace_backward: bool = False,
|
| 378 |
+
) -> torch.Tensor:
|
| 379 |
+
N, V = logits.shape
|
| 380 |
+
BV = min(triton.next_power_of_2(V), 1024 if logit_softcapping is not None else 4096)
|
| 381 |
+
dlogits = logits if inplace_backward else torch.empty_like(logits)
|
| 382 |
+
cross_entropy_bwd_kernel_gluon[(N, triton.cdiv(V, BV))](
|
| 383 |
+
logits=logits,
|
| 384 |
+
target=target,
|
| 385 |
+
lse=lse,
|
| 386 |
+
dloss=dloss,
|
| 387 |
+
dlogits=dlogits,
|
| 388 |
+
s_logits=logits.stride(0),
|
| 389 |
+
s_dloss=dloss.stride(0),
|
| 390 |
+
s_dlogits=dlogits.stride(0),
|
| 391 |
+
label_smoothing=label_smoothing,
|
| 392 |
+
logit_scale=logit_scale,
|
| 393 |
+
lse_square_scale=lse_square_scale,
|
| 394 |
+
logit_softcapping=logit_softcapping,
|
| 395 |
+
ignore_index=ignore_index,
|
| 396 |
+
V=V,
|
| 397 |
+
V_TOTAL=V if total_classes is None else total_classes,
|
| 398 |
+
V_START=class_start_idx,
|
| 399 |
+
BV=BV,
|
| 400 |
+
num_warps=4,
|
| 401 |
+
)
|
| 402 |
+
return dlogits
|
build/torch-cuda/modules/fused_cross_entropy/ops.py
ADDED
|
@@ -0,0 +1,538 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright (c) 2023-2026, Songlin Yang, Yu Zhang, Zhiyuan Li
|
| 2 |
+
#
|
| 3 |
+
# This source code is licensed under the MIT license found in the
|
| 4 |
+
# LICENSE file in the root directory of this source tree.
|
| 5 |
+
# For a list of all contributors, visit:
|
| 6 |
+
# https://github.com/fla-org/flash-linear-attention/graphs/contributors
|
| 7 |
+
|
| 8 |
+
from __future__ import annotations
|
| 9 |
+
|
| 10 |
+
from typing import TYPE_CHECKING
|
| 11 |
+
|
| 12 |
+
import torch
|
| 13 |
+
import torch.nn as nn
|
| 14 |
+
import triton
|
| 15 |
+
import triton.language as tl
|
| 16 |
+
from triton.language.extra.libdevice import tanh
|
| 17 |
+
|
| 18 |
+
from ...backends import dispatch
|
| 19 |
+
from ...ops.utils.op import exp, log
|
| 20 |
+
from ...utils import autocast_custom_bwd, autocast_custom_fwd, input_guard
|
| 21 |
+
|
| 22 |
+
if TYPE_CHECKING:
|
| 23 |
+
from torch.distributed import ProcessGroup
|
| 24 |
+
|
| 25 |
+
|
| 26 |
+
@triton.jit(do_not_specialize=['N'])
|
| 27 |
+
def cross_entropy_fwd_kernel(
|
| 28 |
+
logits, # [N, V]
|
| 29 |
+
target, # [N]
|
| 30 |
+
loss, # [NV, N] or [N] when NV == 1
|
| 31 |
+
z_loss, # [N]
|
| 32 |
+
lse, # [NV, N] or [N] when NV == 1
|
| 33 |
+
s_logits,
|
| 34 |
+
label_smoothing: tl.constexpr,
|
| 35 |
+
logit_scale: tl.constexpr,
|
| 36 |
+
lse_square_scale: tl.constexpr,
|
| 37 |
+
logit_softcapping: tl.constexpr,
|
| 38 |
+
ignore_index: tl.constexpr,
|
| 39 |
+
N,
|
| 40 |
+
V: tl.constexpr,
|
| 41 |
+
V_TOTAL: tl.constexpr,
|
| 42 |
+
V_START: tl.constexpr,
|
| 43 |
+
BV: tl.constexpr,
|
| 44 |
+
SPLIT: tl.constexpr,
|
| 45 |
+
):
|
| 46 |
+
i_n = tl.program_id(0).to(tl.int64)
|
| 47 |
+
i_v = tl.program_id(1)
|
| 48 |
+
o_v = i_v * BV + tl.arange(0, BV)
|
| 49 |
+
m_v = o_v < V
|
| 50 |
+
p_logits = logits + i_n * s_logits
|
| 51 |
+
|
| 52 |
+
# [BV]
|
| 53 |
+
b_logits = tl.load(p_logits + o_v, mask=m_v, other=-float('inf')).to(tl.float32) * logit_scale
|
| 54 |
+
if logit_softcapping is not None:
|
| 55 |
+
b_logits = logit_softcapping * tanh(b_logits / logit_softcapping)
|
| 56 |
+
# these transforms do not preserve -inf in padded lanes
|
| 57 |
+
if logit_softcapping is not None or logit_scale <= 0:
|
| 58 |
+
b_logits = tl.where(m_v, b_logits, -float('inf'))
|
| 59 |
+
if label_smoothing > 0:
|
| 60 |
+
b_sum = tl.sum(tl.where(m_v, b_logits, 0.0), 0)
|
| 61 |
+
b_max = tl.max(b_logits, 0)
|
| 62 |
+
b_lse = log(tl.sum(exp(b_logits - b_max), 0)) + b_max
|
| 63 |
+
|
| 64 |
+
b_target = tl.load(target + i_n).to(tl.int64)
|
| 65 |
+
b_loss = 0.0
|
| 66 |
+
b_z_loss = 0.0
|
| 67 |
+
if b_target != ignore_index:
|
| 68 |
+
b_target -= V_START
|
| 69 |
+
m_target = (b_target >= i_v * BV) & (b_target < tl.minimum(V, (i_v + 1) * BV))
|
| 70 |
+
b_target_logit = tl.load(p_logits + b_target, mask=m_target, other=0).to(tl.float32) * logit_scale
|
| 71 |
+
if logit_softcapping is not None:
|
| 72 |
+
b_target_logit = logit_softcapping * tanh(b_target_logit / logit_softcapping)
|
| 73 |
+
b_loss = -b_target_logit
|
| 74 |
+
if label_smoothing > 0:
|
| 75 |
+
b_loss = (1 - label_smoothing) * b_loss - label_smoothing * b_sum / V_TOTAL
|
| 76 |
+
if not SPLIT:
|
| 77 |
+
b_z_loss = lse_square_scale * b_lse * b_lse
|
| 78 |
+
b_loss += b_lse + b_z_loss
|
| 79 |
+
|
| 80 |
+
tl.store(loss + i_v * N + i_n, b_loss)
|
| 81 |
+
tl.store(lse + i_v * N + i_n, b_lse)
|
| 82 |
+
if not SPLIT:
|
| 83 |
+
tl.store(z_loss + i_n, b_z_loss)
|
| 84 |
+
|
| 85 |
+
|
| 86 |
+
@triton.jit
|
| 87 |
+
def cross_entropy_bwd_kernel(
|
| 88 |
+
logits, # [N, V]
|
| 89 |
+
target, # [N]
|
| 90 |
+
lse, # [N]
|
| 91 |
+
dloss, # [N]
|
| 92 |
+
dlogits, # [N, V]
|
| 93 |
+
s_logits,
|
| 94 |
+
s_dloss,
|
| 95 |
+
s_dlogits,
|
| 96 |
+
label_smoothing: tl.constexpr,
|
| 97 |
+
logit_scale: tl.constexpr,
|
| 98 |
+
lse_square_scale: tl.constexpr,
|
| 99 |
+
logit_softcapping: tl.constexpr,
|
| 100 |
+
ignore_index: tl.constexpr,
|
| 101 |
+
V: tl.constexpr,
|
| 102 |
+
V_TOTAL: tl.constexpr,
|
| 103 |
+
V_START: tl.constexpr,
|
| 104 |
+
BV: tl.constexpr,
|
| 105 |
+
):
|
| 106 |
+
i_n = tl.program_id(0).to(tl.int64)
|
| 107 |
+
i_v = tl.program_id(1).to(tl.int64)
|
| 108 |
+
o_v = i_v * BV + tl.arange(0, BV).to(tl.int64)
|
| 109 |
+
m_v = o_v < V
|
| 110 |
+
p_logits = logits + i_n * s_logits + o_v
|
| 111 |
+
p_dlogits = dlogits + i_n * s_dlogits + o_v
|
| 112 |
+
|
| 113 |
+
b_target = tl.load(target + i_n).to(tl.int64)
|
| 114 |
+
b_dloss = tl.load(dloss + i_n * s_dloss, mask=b_target != ignore_index, other=0).to(tl.float32)
|
| 115 |
+
# [BV]
|
| 116 |
+
b_logits = tl.load(p_logits, mask=m_v, other=0).to(tl.float32) * logit_scale
|
| 117 |
+
if logit_softcapping is not None:
|
| 118 |
+
b_tanh = tanh(b_logits / logit_softcapping)
|
| 119 |
+
b_logits = logit_softcapping * b_tanh
|
| 120 |
+
b_lse = tl.load(lse + i_n)
|
| 121 |
+
# [BV]
|
| 122 |
+
b_probs = exp(b_logits - b_lse)
|
| 123 |
+
b_dlogits = b_probs + 2.0 * lse_square_scale * b_lse * b_probs
|
| 124 |
+
b_target -= V_START
|
| 125 |
+
if label_smoothing > 0:
|
| 126 |
+
b_dlogits -= tl.where(o_v == b_target, 1 - label_smoothing, 0.0)
|
| 127 |
+
b_dlogits -= label_smoothing / V_TOTAL
|
| 128 |
+
else:
|
| 129 |
+
b_dlogits -= tl.where(o_v == b_target, 1.0, 0.0)
|
| 130 |
+
if logit_softcapping is not None:
|
| 131 |
+
b_dlogits *= 1.0 - b_tanh * b_tanh
|
| 132 |
+
b_dlogits *= b_dloss * logit_scale
|
| 133 |
+
tl.store(p_dlogits, b_dlogits, mask=m_v)
|
| 134 |
+
|
| 135 |
+
|
| 136 |
+
@triton.jit(do_not_specialize=['N'])
|
| 137 |
+
def cross_entropy_fwd_kernel_reduce(
|
| 138 |
+
partial_loss,
|
| 139 |
+
partial_lse,
|
| 140 |
+
target,
|
| 141 |
+
loss,
|
| 142 |
+
z_loss,
|
| 143 |
+
lse,
|
| 144 |
+
lse_square_scale: tl.constexpr,
|
| 145 |
+
ignore_index: tl.constexpr,
|
| 146 |
+
N,
|
| 147 |
+
NV: tl.constexpr,
|
| 148 |
+
BN: tl.constexpr,
|
| 149 |
+
BS: tl.constexpr,
|
| 150 |
+
SPLIT: tl.constexpr,
|
| 151 |
+
REDUCE_LOSS: tl.constexpr,
|
| 152 |
+
):
|
| 153 |
+
o_n = tl.program_id(0).to(tl.int64) * BN + tl.arange(0, BN)
|
| 154 |
+
o_s = tl.arange(0, BS).to(tl.int64)
|
| 155 |
+
offsets = o_s[:, None] * N + o_n[None, :]
|
| 156 |
+
mask = (o_s[:, None] < NV) & (o_n[None, :] < N)
|
| 157 |
+
b_lse = tl.load(partial_lse + offsets, mask=mask, other=-float('inf')).to(tl.float32)
|
| 158 |
+
b_max = tl.max(b_lse, 0)
|
| 159 |
+
b_lse = b_max + log(tl.sum(exp(b_lse - b_max[None, :]), 0))
|
| 160 |
+
if REDUCE_LOSS:
|
| 161 |
+
b_loss = tl.sum(tl.load(partial_loss + offsets, mask=mask, other=0).to(tl.float32), 0)
|
| 162 |
+
else:
|
| 163 |
+
b_loss = tl.load(partial_loss + o_n, mask=o_n < N, other=0).to(tl.float32)
|
| 164 |
+
if not SPLIT:
|
| 165 |
+
valid = tl.load(target + o_n, mask=o_n < N, other=ignore_index) != ignore_index
|
| 166 |
+
b_z_loss = tl.where(valid, lse_square_scale * b_lse * b_lse, 0.)
|
| 167 |
+
b_loss = tl.where(valid, b_loss + b_lse + b_z_loss, 0.)
|
| 168 |
+
tl.store(z_loss + o_n, b_z_loss, mask=o_n < N)
|
| 169 |
+
tl.store(loss + o_n, b_loss, mask=o_n < N)
|
| 170 |
+
tl.store(lse + o_n, b_lse, mask=o_n < N)
|
| 171 |
+
|
| 172 |
+
|
| 173 |
+
def cross_entropy_reduce(
|
| 174 |
+
loss: torch.Tensor,
|
| 175 |
+
z_loss: torch.Tensor,
|
| 176 |
+
lse: torch.Tensor,
|
| 177 |
+
target: torch.Tensor,
|
| 178 |
+
lse_square_scale: float,
|
| 179 |
+
ignore_index: int,
|
| 180 |
+
process_group: ProcessGroup | None,
|
| 181 |
+
) -> tuple[torch.Tensor, torch.Tensor, torch.Tensor]:
|
| 182 |
+
N = target.shape[0]
|
| 183 |
+
world_size = 1 if process_group is None else torch.distributed.get_world_size(group=process_group)
|
| 184 |
+
if lse.ndim == 2:
|
| 185 |
+
NV = lse.shape[0]
|
| 186 |
+
reduced_loss = loss.new_empty(N)
|
| 187 |
+
reduced_lse = torch.empty_like(reduced_loss)
|
| 188 |
+
cross_entropy_fwd_kernel_reduce[(triton.cdiv(N, 128),)](
|
| 189 |
+
partial_loss=loss,
|
| 190 |
+
partial_lse=lse,
|
| 191 |
+
target=target,
|
| 192 |
+
loss=reduced_loss,
|
| 193 |
+
z_loss=z_loss,
|
| 194 |
+
lse=reduced_lse,
|
| 195 |
+
lse_square_scale=lse_square_scale,
|
| 196 |
+
ignore_index=ignore_index,
|
| 197 |
+
N=N,
|
| 198 |
+
NV=NV,
|
| 199 |
+
BN=128,
|
| 200 |
+
BS=triton.next_power_of_2(NV),
|
| 201 |
+
SPLIT=world_size > 1,
|
| 202 |
+
REDUCE_LOSS=True,
|
| 203 |
+
num_warps=4,
|
| 204 |
+
)
|
| 205 |
+
loss, lse = reduced_loss, reduced_lse
|
| 206 |
+
if world_size > 1:
|
| 207 |
+
gathered_lse = lse.new_empty(world_size, N)
|
| 208 |
+
torch.distributed.all_gather_into_tensor(output_tensor=gathered_lse, input_tensor=lse, group=process_group)
|
| 209 |
+
torch.distributed.all_reduce(tensor=loss, group=process_group)
|
| 210 |
+
cross_entropy_fwd_kernel_reduce[(triton.cdiv(N, 128),)](
|
| 211 |
+
partial_loss=loss,
|
| 212 |
+
partial_lse=gathered_lse,
|
| 213 |
+
target=target,
|
| 214 |
+
loss=loss,
|
| 215 |
+
z_loss=z_loss,
|
| 216 |
+
lse=lse,
|
| 217 |
+
lse_square_scale=lse_square_scale,
|
| 218 |
+
ignore_index=ignore_index,
|
| 219 |
+
N=N,
|
| 220 |
+
NV=world_size,
|
| 221 |
+
BN=128,
|
| 222 |
+
BS=triton.next_power_of_2(world_size),
|
| 223 |
+
SPLIT=False,
|
| 224 |
+
REDUCE_LOSS=False,
|
| 225 |
+
num_warps=4,
|
| 226 |
+
)
|
| 227 |
+
return loss, z_loss, lse
|
| 228 |
+
|
| 229 |
+
|
| 230 |
+
@dispatch
|
| 231 |
+
def cross_entropy_fwd(
|
| 232 |
+
logits: torch.Tensor,
|
| 233 |
+
target: torch.Tensor,
|
| 234 |
+
label_smoothing: float = 0.0,
|
| 235 |
+
logit_scale: float = 1.0,
|
| 236 |
+
lse_square_scale: float = 0.0,
|
| 237 |
+
logit_softcapping: float | None = None,
|
| 238 |
+
ignore_index: int = -100,
|
| 239 |
+
process_group: ProcessGroup | None = None,
|
| 240 |
+
):
|
| 241 |
+
N, V = logits.shape
|
| 242 |
+
assert target.shape == (N,)
|
| 243 |
+
world_size = 1 if process_group is None else torch.distributed.get_world_size(group=process_group)
|
| 244 |
+
total_classes = world_size * V
|
| 245 |
+
rank = 0 if process_group is None else torch.distributed.get_rank(group=process_group)
|
| 246 |
+
class_start_idx = rank * V
|
| 247 |
+
|
| 248 |
+
if logits.stride(-1) != 1:
|
| 249 |
+
logits = logits.contiguous()
|
| 250 |
+
BV = min(triton.next_power_of_2(V), 64 * 1024)
|
| 251 |
+
# reduce softcap register pressure without introducing an additional split reduction
|
| 252 |
+
if logit_softcapping is not None and V > BV:
|
| 253 |
+
BV = 8 * 1024
|
| 254 |
+
num_warps = 4 if BV < 2048 else (8 if BV < 8192 else 16)
|
| 255 |
+
# vocab partitions contribute partial loss until the global LSE is available
|
| 256 |
+
NV = triton.cdiv(V, BV)
|
| 257 |
+
split = world_size > 1 or NV > 1
|
| 258 |
+
shape = (NV, N) if NV > 1 else (N,)
|
| 259 |
+
loss = logits.new_empty(shape, dtype=torch.float)
|
| 260 |
+
lse = torch.empty_like(loss)
|
| 261 |
+
z_loss = logits.new_empty(N, dtype=torch.float)
|
| 262 |
+
|
| 263 |
+
cross_entropy_fwd_kernel[(N, NV)](
|
| 264 |
+
logits=logits,
|
| 265 |
+
target=target,
|
| 266 |
+
loss=loss,
|
| 267 |
+
z_loss=z_loss,
|
| 268 |
+
lse=lse,
|
| 269 |
+
s_logits=logits.stride(0),
|
| 270 |
+
label_smoothing=label_smoothing,
|
| 271 |
+
logit_scale=logit_scale,
|
| 272 |
+
lse_square_scale=lse_square_scale,
|
| 273 |
+
logit_softcapping=logit_softcapping,
|
| 274 |
+
ignore_index=ignore_index,
|
| 275 |
+
N=N,
|
| 276 |
+
V=V,
|
| 277 |
+
V_TOTAL=total_classes,
|
| 278 |
+
V_START=class_start_idx,
|
| 279 |
+
BV=BV,
|
| 280 |
+
SPLIT=split,
|
| 281 |
+
num_warps=num_warps,
|
| 282 |
+
)
|
| 283 |
+
|
| 284 |
+
if split:
|
| 285 |
+
loss, z_loss, lse = cross_entropy_reduce(
|
| 286 |
+
loss=loss,
|
| 287 |
+
z_loss=z_loss,
|
| 288 |
+
lse=lse,
|
| 289 |
+
target=target,
|
| 290 |
+
lse_square_scale=lse_square_scale,
|
| 291 |
+
ignore_index=ignore_index,
|
| 292 |
+
process_group=process_group,
|
| 293 |
+
)
|
| 294 |
+
|
| 295 |
+
return loss, z_loss, lse, total_classes, class_start_idx
|
| 296 |
+
|
| 297 |
+
|
| 298 |
+
@dispatch
|
| 299 |
+
def cross_entropy_bwd(
|
| 300 |
+
logits: torch.Tensor,
|
| 301 |
+
target: torch.Tensor,
|
| 302 |
+
lse: torch.Tensor,
|
| 303 |
+
dloss: torch.Tensor,
|
| 304 |
+
label_smoothing: float = 0.0,
|
| 305 |
+
logit_scale: float = 1.0,
|
| 306 |
+
lse_square_scale: float = 0.0,
|
| 307 |
+
logit_softcapping: float | None = None,
|
| 308 |
+
ignore_index: int = -100,
|
| 309 |
+
total_classes: int | None = None,
|
| 310 |
+
class_start_idx: int = 0,
|
| 311 |
+
inplace_backward: bool = False,
|
| 312 |
+
):
|
| 313 |
+
N, V = logits.shape
|
| 314 |
+
BV = min(triton.next_power_of_2(V), 4 * 1024)
|
| 315 |
+
dlogits = logits if inplace_backward else torch.empty_like(logits)
|
| 316 |
+
cross_entropy_bwd_kernel[(N, triton.cdiv(V, BV))](
|
| 317 |
+
logits=logits,
|
| 318 |
+
target=target,
|
| 319 |
+
lse=lse,
|
| 320 |
+
dloss=dloss,
|
| 321 |
+
dlogits=dlogits,
|
| 322 |
+
s_logits=logits.stride(0),
|
| 323 |
+
s_dloss=dloss.stride(0),
|
| 324 |
+
s_dlogits=dlogits.stride(0),
|
| 325 |
+
label_smoothing=label_smoothing,
|
| 326 |
+
logit_scale=logit_scale,
|
| 327 |
+
lse_square_scale=lse_square_scale,
|
| 328 |
+
logit_softcapping=logit_softcapping,
|
| 329 |
+
ignore_index=ignore_index,
|
| 330 |
+
V=V,
|
| 331 |
+
V_TOTAL=V if total_classes is None else total_classes,
|
| 332 |
+
V_START=class_start_idx,
|
| 333 |
+
BV=BV,
|
| 334 |
+
num_warps=4 if BV < 2048 else 8,
|
| 335 |
+
)
|
| 336 |
+
return dlogits
|
| 337 |
+
|
| 338 |
+
|
| 339 |
+
class FusedCrossEntropyFunction(torch.autograd.Function):
|
| 340 |
+
|
| 341 |
+
@staticmethod
|
| 342 |
+
@input_guard
|
| 343 |
+
@autocast_custom_fwd
|
| 344 |
+
def forward(
|
| 345 |
+
ctx,
|
| 346 |
+
logits,
|
| 347 |
+
target,
|
| 348 |
+
label_smoothing=0.0,
|
| 349 |
+
logit_scale=1.0,
|
| 350 |
+
lse_square_scale=0.0,
|
| 351 |
+
logit_softcapping=None,
|
| 352 |
+
ignore_index=-100,
|
| 353 |
+
inplace_backward=False,
|
| 354 |
+
process_group: ProcessGroup | None = None,
|
| 355 |
+
):
|
| 356 |
+
loss, z_loss, lse, total_classes, class_start_idx = cross_entropy_fwd(
|
| 357 |
+
logits=logits,
|
| 358 |
+
target=target,
|
| 359 |
+
label_smoothing=label_smoothing,
|
| 360 |
+
logit_scale=logit_scale,
|
| 361 |
+
lse_square_scale=lse_square_scale,
|
| 362 |
+
logit_softcapping=logit_softcapping,
|
| 363 |
+
ignore_index=ignore_index,
|
| 364 |
+
process_group=process_group,
|
| 365 |
+
)
|
| 366 |
+
ctx.save_for_backward(logits, target, lse)
|
| 367 |
+
ctx.mark_non_differentiable(z_loss)
|
| 368 |
+
ctx.label_smoothing = label_smoothing
|
| 369 |
+
ctx.logit_scale = logit_scale
|
| 370 |
+
ctx.lse_square_scale = lse_square_scale
|
| 371 |
+
ctx.logit_softcapping = logit_softcapping
|
| 372 |
+
ctx.ignore_index = ignore_index
|
| 373 |
+
ctx.total_classes = total_classes
|
| 374 |
+
ctx.class_start_idx = class_start_idx
|
| 375 |
+
ctx.inplace_backward = inplace_backward
|
| 376 |
+
|
| 377 |
+
return loss, z_loss
|
| 378 |
+
|
| 379 |
+
@staticmethod
|
| 380 |
+
@input_guard
|
| 381 |
+
@autocast_custom_bwd
|
| 382 |
+
def backward(ctx, dloss, dz_loss):
|
| 383 |
+
# z-loss is returned for logging and is already included in the differentiable loss
|
| 384 |
+
del dz_loss
|
| 385 |
+
|
| 386 |
+
logits, target, lse = ctx.saved_tensors
|
| 387 |
+
dlogits = cross_entropy_bwd(
|
| 388 |
+
logits=logits,
|
| 389 |
+
target=target,
|
| 390 |
+
lse=lse,
|
| 391 |
+
dloss=dloss,
|
| 392 |
+
label_smoothing=ctx.label_smoothing,
|
| 393 |
+
logit_scale=ctx.logit_scale,
|
| 394 |
+
lse_square_scale=ctx.lse_square_scale,
|
| 395 |
+
logit_softcapping=ctx.logit_softcapping,
|
| 396 |
+
ignore_index=ctx.ignore_index,
|
| 397 |
+
total_classes=ctx.total_classes,
|
| 398 |
+
class_start_idx=ctx.class_start_idx,
|
| 399 |
+
inplace_backward=ctx.inplace_backward,
|
| 400 |
+
)
|
| 401 |
+
return dlogits, None, None, None, None, None, None, None, None
|
| 402 |
+
|
| 403 |
+
|
| 404 |
+
fused_cross_entropy_forward = cross_entropy_fwd
|
| 405 |
+
|
| 406 |
+
|
| 407 |
+
CrossEntropyLossFunction = FusedCrossEntropyFunction
|
| 408 |
+
|
| 409 |
+
|
| 410 |
+
@dispatch
|
| 411 |
+
def cross_entropy_loss(
|
| 412 |
+
logits: torch.Tensor,
|
| 413 |
+
target: torch.Tensor,
|
| 414 |
+
label_smoothing: float = 0.0,
|
| 415 |
+
logit_scale: float = 1.0,
|
| 416 |
+
lse_square_scale: float = 0.0,
|
| 417 |
+
logit_softcapping: float | None = None,
|
| 418 |
+
ignore_index: int = -100,
|
| 419 |
+
inplace_backward: bool = False,
|
| 420 |
+
process_group: ProcessGroup | None = None,
|
| 421 |
+
) -> tuple[torch.Tensor, torch.Tensor]:
|
| 422 |
+
"""Compute unreduced cross entropy and its non-differentiable z-loss component.
|
| 423 |
+
|
| 424 |
+
Args:
|
| 425 |
+
logits (torch.Tensor):
|
| 426 |
+
Input logits of shape `[N, V]`.
|
| 427 |
+
target (torch.Tensor):
|
| 428 |
+
Global target indices of shape `[N]`.
|
| 429 |
+
label_smoothing (float, Optional):
|
| 430 |
+
Uniform label smoothing coefficient. Default: 0.0.
|
| 431 |
+
logit_scale (float, Optional):
|
| 432 |
+
Scale applied before softcapping. Default: 1.0.
|
| 433 |
+
lse_square_scale (float, Optional):
|
| 434 |
+
Coefficient of the squared logsumexp regularizer. Default: 0.0.
|
| 435 |
+
logit_softcapping (float, Optional):
|
| 436 |
+
Softcap applied as `softcap * tanh(logits / softcap)`. Default: `None`.
|
| 437 |
+
ignore_index (int, Optional):
|
| 438 |
+
Target index excluded from loss and gradients. Default: -100.
|
| 439 |
+
inplace_backward (bool, Optional):
|
| 440 |
+
Whether to overwrite logits with their gradients. Default: `False`.
|
| 441 |
+
process_group (ProcessGroup, Optional):
|
| 442 |
+
Group sharding the vocabulary into equal contiguous partitions. Default: `None`.
|
| 443 |
+
|
| 444 |
+
Returns:
|
| 445 |
+
tuple[torch.Tensor, torch.Tensor]:
|
| 446 |
+
FP32 loss and z-loss tensors of shape `[N]`. The loss includes z-loss.
|
| 447 |
+
"""
|
| 448 |
+
return FusedCrossEntropyFunction.apply(
|
| 449 |
+
logits,
|
| 450 |
+
target,
|
| 451 |
+
label_smoothing,
|
| 452 |
+
logit_scale,
|
| 453 |
+
lse_square_scale,
|
| 454 |
+
logit_softcapping,
|
| 455 |
+
ignore_index,
|
| 456 |
+
inplace_backward,
|
| 457 |
+
process_group,
|
| 458 |
+
)
|
| 459 |
+
|
| 460 |
+
|
| 461 |
+
class FusedCrossEntropyLoss(nn.Module):
|
| 462 |
+
def __init__(
|
| 463 |
+
self,
|
| 464 |
+
ignore_index: int = -100,
|
| 465 |
+
reduction: str = "mean",
|
| 466 |
+
label_smoothing: float = 0.0,
|
| 467 |
+
logit_scale: float = 1.0,
|
| 468 |
+
lse_square_scale: float = 0.0,
|
| 469 |
+
logit_softcapping: float | None = None,
|
| 470 |
+
inplace_backward: bool = False,
|
| 471 |
+
process_group: ProcessGroup | None = None,
|
| 472 |
+
return_z_loss: bool = False,
|
| 473 |
+
):
|
| 474 |
+
"""Cross entropy with optional logit transforms and vocabulary parallelism.
|
| 475 |
+
|
| 476 |
+
Args:
|
| 477 |
+
ignore_index (int, Optional):
|
| 478 |
+
Target index excluded from loss and gradients. Default: -100.
|
| 479 |
+
reduction (str, Optional):
|
| 480 |
+
Reduction over non-ignored targets: `mean`, `sum`, or `none`. Default: `mean`.
|
| 481 |
+
label_smoothing (float, Optional):
|
| 482 |
+
Uniform label smoothing coefficient. Default: 0.0.
|
| 483 |
+
logit_scale (float, Optional):
|
| 484 |
+
Scale applied before softcapping. Default: 1.0.
|
| 485 |
+
lse_square_scale (float, Optional):
|
| 486 |
+
Coefficient of the squared logsumexp regularizer. Default: 0.0.
|
| 487 |
+
logit_softcapping (float, Optional):
|
| 488 |
+
Softcap applied as `softcap * tanh(logits / softcap)`. Default: `None`.
|
| 489 |
+
inplace_backward (bool, Optional):
|
| 490 |
+
Whether to overwrite logits with their gradients. Default: `False`.
|
| 491 |
+
process_group (ProcessGroup, Optional):
|
| 492 |
+
Group sharding the vocabulary into equal contiguous partitions. Default: `None`.
|
| 493 |
+
return_z_loss (bool, Optional):
|
| 494 |
+
Whether to also return z-loss for logging, without its own backward. Default: `False`.
|
| 495 |
+
"""
|
| 496 |
+
super().__init__()
|
| 497 |
+
if reduction not in ('mean', 'sum', 'none'):
|
| 498 |
+
raise NotImplementedError(f"Unsupported reduction: {reduction}")
|
| 499 |
+
self.ignore_index = ignore_index
|
| 500 |
+
self.reduction = reduction
|
| 501 |
+
self.label_smoothing = label_smoothing
|
| 502 |
+
self.logit_scale = logit_scale
|
| 503 |
+
self.lse_square_scale = lse_square_scale
|
| 504 |
+
self.logit_softcapping = logit_softcapping
|
| 505 |
+
self.inplace_backward = inplace_backward
|
| 506 |
+
self.process_group = process_group
|
| 507 |
+
self.return_z_loss = return_z_loss
|
| 508 |
+
|
| 509 |
+
def forward(self, input: torch.Tensor, target: torch.Tensor):
|
| 510 |
+
"""Compute loss from `[N, V]` logits and `[N]` targets.
|
| 511 |
+
|
| 512 |
+
Return FP32 scalars for `mean` or `sum`, and `[N]` tensors for `none`.
|
| 513 |
+
When `return_z_loss=True`, also return the reduced z-loss component.
|
| 514 |
+
"""
|
| 515 |
+
assert input.device.type in ('cuda', 'npu', 'xpu') and target.device.type in ('cuda', 'npu', 'xpu'), (
|
| 516 |
+
"Only support CUDA/NPU/XPU tensors"
|
| 517 |
+
)
|
| 518 |
+
loss, z_loss = cross_entropy_loss(
|
| 519 |
+
logits=input,
|
| 520 |
+
target=target,
|
| 521 |
+
label_smoothing=self.label_smoothing,
|
| 522 |
+
logit_scale=self.logit_scale,
|
| 523 |
+
lse_square_scale=self.lse_square_scale,
|
| 524 |
+
logit_softcapping=self.logit_softcapping,
|
| 525 |
+
ignore_index=self.ignore_index,
|
| 526 |
+
inplace_backward=self.inplace_backward,
|
| 527 |
+
process_group=self.process_group,
|
| 528 |
+
)
|
| 529 |
+
if self.reduction != 'none':
|
| 530 |
+
loss = loss.sum()
|
| 531 |
+
if self.return_z_loss:
|
| 532 |
+
z_loss = z_loss.sum()
|
| 533 |
+
if self.reduction == 'mean':
|
| 534 |
+
total = (target != self.ignore_index).sum()
|
| 535 |
+
loss = loss / total
|
| 536 |
+
if self.return_z_loss:
|
| 537 |
+
z_loss = z_loss / total
|
| 538 |
+
return (loss, z_loss) if self.return_z_loss else loss
|
build/torch-cuda/modules/fused_kl_div/__init__.py
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright (c) 2023-2026, Songlin Yang, Yu Zhang, Zhiyuan Li
|
| 2 |
+
#
|
| 3 |
+
# This source code is licensed under the MIT license found in the
|
| 4 |
+
# LICENSE file in the root directory of this source tree.
|
| 5 |
+
# For a list of all contributors, visit:
|
| 6 |
+
# https://github.com/fla-org/flash-linear-attention/graphs/contributors
|
| 7 |
+
|
| 8 |
+
from ...modules.fused_kl_div.ops import FusedKLDivLoss, fused_kl_div_loss
|
| 9 |
+
|
| 10 |
+
__all__ = ['FusedKLDivLoss', 'fused_kl_div_loss']
|
| 11 |
+
|
build/torch-cuda/modules/{fused_kl_div.py → fused_kl_div/ops.py}
RENAMED
|
@@ -11,14 +11,14 @@ import torch.nn.functional as F
|
|
| 11 |
import triton
|
| 12 |
import triton.language as tl
|
| 13 |
|
| 14 |
-
from ..
|
| 15 |
-
from ..ops.utils.op import exp, log
|
| 16 |
-
from ..utils import IS_AMD, input_guard
|
| 17 |
|
| 18 |
-
#
|
| 19 |
# https://github.com/triton-lang/triton/blob/ba42a5c68fd0505f8c42f4202d53be0f8d9a5fe0/python/triton/language/core.py#L19
|
| 20 |
-
#
|
| 21 |
-
#
|
| 22 |
MAX_FUSED_SIZE = 65536 // 2
|
| 23 |
STATIC_WARPS = 32 if not IS_AMD else 16
|
| 24 |
|
|
@@ -42,22 +42,19 @@ def kl_div_kernel(
|
|
| 42 |
logits += i_n * s_logits
|
| 43 |
target_logits += i_n * s_logits
|
| 44 |
|
| 45 |
-
#
|
| 46 |
sm = float('-inf')
|
| 47 |
tm = float('-inf')
|
| 48 |
-
# d is the sum. use the notation from the paper
|
| 49 |
sd, td = 0.0, 0.0
|
| 50 |
|
| 51 |
NV = tl.cdiv(V, BV)
|
| 52 |
for iv in range(0, NV):
|
| 53 |
o_x = iv * BV + tl.arange(0, BV)
|
| 54 |
-
# for student
|
| 55 |
b_sl = tl.load(logits + o_x, mask=o_x < V, other=float('-inf'))
|
| 56 |
b_sm = tl.max(b_sl)
|
| 57 |
m_new = tl.maximum(sm, b_sm)
|
| 58 |
sd = sd * exp(sm - m_new) + tl.sum(exp(b_sl - m_new))
|
| 59 |
sm = m_new
|
| 60 |
-
# for teacher
|
| 61 |
b_tl = tl.load(target_logits + o_x, mask=o_x < V, other=float('-inf'))
|
| 62 |
b_tm = tl.max(b_tl)
|
| 63 |
m_new = tl.maximum(tm, b_tm)
|
|
@@ -89,45 +86,28 @@ def kl_div_kernel(
|
|
| 89 |
|
| 90 |
|
| 91 |
@triton.jit
|
| 92 |
-
def elementwise_mul_kernel(
|
| 93 |
-
x,
|
| 94 |
-
g,
|
| 95 |
-
N: tl.constexpr,
|
| 96 |
-
B: tl.constexpr,
|
| 97 |
-
):
|
| 98 |
-
"""
|
| 99 |
-
This function multiplies each element of the tensor pointed by x with the value pointed by g.
|
| 100 |
-
The multiplication is performed in-place on the tensor pointed by x.
|
| 101 |
-
|
| 102 |
-
Parameters:
|
| 103 |
-
x:
|
| 104 |
-
Pointer to the input tensor.
|
| 105 |
-
g:
|
| 106 |
-
Pointer to the gradient output value.
|
| 107 |
-
N (int):
|
| 108 |
-
The number of columns in the input tensor.
|
| 109 |
-
B (int):
|
| 110 |
-
The block size for Triton operations.
|
| 111 |
-
"""
|
| 112 |
|
| 113 |
-
# Get the program ID and convert it to int64 to avoid overflow
|
| 114 |
i_x = tl.program_id(0).to(tl.int64)
|
| 115 |
o_x = i_x * B + tl.arange(0, B)
|
| 116 |
|
| 117 |
-
# Load the gradient output value
|
| 118 |
b_g = tl.load(g)
|
|
|
|
|
|
|
| 119 |
b_x = tl.load(x + o_x, mask=o_x < N)
|
| 120 |
tl.store(x + o_x, b_x * b_g, mask=o_x < N)
|
| 121 |
|
| 122 |
|
| 123 |
-
@dispatch
|
| 124 |
-
def
|
| 125 |
x: torch.Tensor,
|
| 126 |
target_x: torch.Tensor,
|
| 127 |
weight: torch.Tensor,
|
| 128 |
target_weight: torch.Tensor,
|
| 129 |
reduction: str = 'batchmean',
|
| 130 |
accumulate_grad_in_fp32: bool = True,
|
|
|
|
|
|
|
| 131 |
):
|
| 132 |
device = x.device
|
| 133 |
|
|
@@ -146,9 +126,8 @@ def fused_kl_div_forward(
|
|
| 146 |
|
| 147 |
grad_dtype = torch.float32 if accumulate_grad_in_fp32 else weight.dtype
|
| 148 |
|
| 149 |
-
dx = torch.zeros_like(x, device=device)
|
| 150 |
-
dw = torch.zeros_like(weight, device=device, dtype=grad_dtype) if
|
| 151 |
-
# we use fp32 for loss accumulator
|
| 152 |
loss = torch.zeros(N, dtype=torch.float32, device=device)
|
| 153 |
|
| 154 |
for ic in range(NC):
|
|
@@ -156,14 +135,12 @@ def fused_kl_div_forward(
|
|
| 156 |
# [C, N]
|
| 157 |
c_sx = x[start:end]
|
| 158 |
c_tx = target_x[start:end]
|
| 159 |
-
# when doing matmul, use the original precision
|
| 160 |
# [C, V]
|
| 161 |
c_sl = F.linear(c_sx, weight)
|
| 162 |
c_tl = F.linear(c_tx, target_weight)
|
| 163 |
-
if
|
| 164 |
c_sx = c_sx.to(dtype=grad_dtype)
|
| 165 |
|
| 166 |
-
# unreduced loss
|
| 167 |
c_loss = loss[start:end]
|
| 168 |
|
| 169 |
# Here we calculate the gradient of c_sx in place so we can save memory.
|
|
@@ -187,15 +164,11 @@ def fused_kl_div_forward(
|
|
| 187 |
# Thus, we need an additional scaling factor of (n_non_ignore/total) to scale the gradients.
|
| 188 |
# [C, H]
|
| 189 |
|
| 190 |
-
dx
|
|
|
|
| 191 |
|
| 192 |
-
if
|
| 193 |
-
torch.addmm(
|
| 194 |
-
input=dw,
|
| 195 |
-
mat1=c_sl.t().to(dtype=grad_dtype),
|
| 196 |
-
mat2=c_sx,
|
| 197 |
-
out=dw,
|
| 198 |
-
)
|
| 199 |
|
| 200 |
loss = loss.sum()
|
| 201 |
if dw is not None:
|
|
@@ -203,37 +176,15 @@ def fused_kl_div_forward(
|
|
| 203 |
return loss, dx, dw
|
| 204 |
|
| 205 |
|
| 206 |
-
@dispatch
|
| 207 |
-
def
|
| 208 |
-
|
| 209 |
-
|
| 210 |
-
|
| 211 |
-
|
| 212 |
-
|
| 213 |
-
if torch.ne(do, torch.tensor(1.0, device=do.device)):
|
| 214 |
-
# We use a Triton kernel instead of a PyTorch operation because modifying inputs in-place
|
| 215 |
-
# for gradient storage and backward multiple times causes anomalies with PyTorch but not with Triton.
|
| 216 |
-
N, H = dx.shape
|
| 217 |
B = min(MAX_FUSED_SIZE, triton.next_power_of_2(H))
|
| 218 |
-
|
| 219 |
-
elementwise_mul_kernel[(triton.cdiv(N * H, B),)](
|
| 220 |
-
x=dx,
|
| 221 |
-
g=do,
|
| 222 |
-
N=N*H,
|
| 223 |
-
B=B,
|
| 224 |
-
num_warps=STATIC_WARPS,
|
| 225 |
-
)
|
| 226 |
-
|
| 227 |
-
# handle dw
|
| 228 |
-
if dw is not None:
|
| 229 |
-
V, H = dw.shape
|
| 230 |
-
elementwise_mul_kernel[(triton.cdiv(V * H, B),)](
|
| 231 |
-
x=dw,
|
| 232 |
-
g=do,
|
| 233 |
-
N=V*H,
|
| 234 |
-
B=B,
|
| 235 |
-
num_warps=STATIC_WARPS,
|
| 236 |
-
)
|
| 237 |
|
| 238 |
return dx, dw
|
| 239 |
|
|
@@ -250,14 +201,17 @@ class FusedKLDivLossFunction(torch.autograd.Function):
|
|
| 250 |
target_weight: torch.Tensor,
|
| 251 |
reduction: str,
|
| 252 |
accumulate_grad_in_fp32: bool,
|
|
|
|
| 253 |
):
|
| 254 |
-
loss, dx, dw =
|
| 255 |
x=x,
|
| 256 |
target_x=target_x,
|
| 257 |
weight=weight,
|
| 258 |
target_weight=target_weight,
|
| 259 |
reduction=reduction,
|
| 260 |
accumulate_grad_in_fp32=accumulate_grad_in_fp32,
|
|
|
|
|
|
|
| 261 |
)
|
| 262 |
ctx.save_for_backward(dx, dw)
|
| 263 |
return loss
|
|
@@ -266,8 +220,8 @@ class FusedKLDivLossFunction(torch.autograd.Function):
|
|
| 266 |
@input_guard
|
| 267 |
def backward(ctx, do):
|
| 268 |
dx, dw = ctx.saved_tensors
|
| 269 |
-
dx, dw =
|
| 270 |
-
return dx, None, dw, None, None, None
|
| 271 |
|
| 272 |
|
| 273 |
def fused_kl_div_loss(
|
|
@@ -280,23 +234,25 @@ def fused_kl_div_loss(
|
|
| 280 |
) -> tuple[torch.Tensor, torch.Tensor]:
|
| 281 |
"""
|
| 282 |
Args:
|
| 283 |
-
x (
|
| 284 |
Tensor of shape `[batch_size * seq_len, hidden_size]`.
|
| 285 |
-
target_x (
|
| 286 |
Frozen teacher input tensor of shape `[batch_size * seq_len, hidden_size]`.
|
| 287 |
Must not require gradients.
|
| 288 |
-
weight (
|
| 289 |
Tensor of shape `[vocab_size, hidden_size]`.
|
| 290 |
-
target_weight (
|
| 291 |
Frozen teacher weight tensor of shape `[vocab_size, hidden_size]`.
|
| 292 |
Must not require gradients.
|
| 293 |
-
reduction (
|
| 294 |
Specifies the reduction to apply to the output: 'batchmean'. Default: 'batchmean'.
|
| 295 |
-
accumulate_grad_in_fp32 (
|
| 296 |
-
Whether to accumulate the student weight gradient in fp32 before casting it back
|
| 297 |
-
|
|
|
|
| 298 |
Returns:
|
| 299 |
-
loss
|
|
|
|
| 300 |
"""
|
| 301 |
if target_x.requires_grad or target_weight.requires_grad:
|
| 302 |
raise RuntimeError(
|
|
@@ -311,26 +267,24 @@ def fused_kl_div_loss(
|
|
| 311 |
target_weight,
|
| 312 |
reduction,
|
| 313 |
accumulate_grad_in_fp32,
|
|
|
|
| 314 |
)
|
| 315 |
|
| 316 |
|
| 317 |
class FusedKLDivLoss(nn.Module):
|
| 318 |
|
| 319 |
-
def __init__(
|
| 320 |
-
self,
|
| 321 |
-
reduction: str = 'batchmean',
|
| 322 |
-
accumulate_grad_in_fp32: bool = True,
|
| 323 |
-
):
|
| 324 |
"""
|
| 325 |
Args:
|
| 326 |
-
reduction (
|
| 327 |
Specifies the reduction to apply to the output: 'batchmean'. Default: 'batchmean'.
|
| 328 |
-
accumulate_grad_in_fp32 (
|
| 329 |
-
Whether to accumulate the student weight gradient in fp32 before casting it back
|
| 330 |
-
|
|
|
|
| 331 |
Note:
|
| 332 |
-
FusedKLDivLoss only computes gradients for `x` and `weight`;
|
| 333 |
-
`target_weight` are treated as frozen teacher tensors and must not require gradients.
|
| 334 |
"""
|
| 335 |
super().__init__()
|
| 336 |
|
|
@@ -339,27 +293,23 @@ class FusedKLDivLoss(nn.Module):
|
|
| 339 |
self.reduction = reduction
|
| 340 |
self.accumulate_grad_in_fp32 = accumulate_grad_in_fp32
|
| 341 |
|
| 342 |
-
def forward(
|
| 343 |
-
self,
|
| 344 |
-
x: torch.Tensor,
|
| 345 |
-
target_x: torch.Tensor,
|
| 346 |
-
weight: torch.Tensor,
|
| 347 |
-
target_weight: torch.Tensor,
|
| 348 |
-
):
|
| 349 |
"""
|
| 350 |
Args:
|
| 351 |
-
x (
|
| 352 |
Tensor of shape `[batch_size * seq_len, hidden_size]`.
|
| 353 |
-
target_x (
|
| 354 |
Frozen teacher input tensor of shape `[batch_size * seq_len, hidden_size]`.
|
| 355 |
Must not require gradients.
|
| 356 |
-
weight (
|
| 357 |
Tensor of shape `[vocab_size, hidden_size]`.
|
| 358 |
-
target_weight (
|
| 359 |
Frozen teacher weight tensor of shape `[vocab_size, hidden_size]`.
|
| 360 |
Must not require gradients.
|
|
|
|
| 361 |
Returns:
|
| 362 |
-
loss
|
|
|
|
| 363 |
"""
|
| 364 |
loss = fused_kl_div_loss(
|
| 365 |
x=x,
|
|
|
|
| 11 |
import triton
|
| 12 |
import triton.language as tl
|
| 13 |
|
| 14 |
+
from ...backends import dispatch
|
| 15 |
+
from ...ops.utils.op import exp, log
|
| 16 |
+
from ...utils import IS_AMD, input_guard
|
| 17 |
|
| 18 |
+
# the hard limit of TRITON_MAX_TENSOR_NUMEL is 1048576
|
| 19 |
# https://github.com/triton-lang/triton/blob/ba42a5c68fd0505f8c42f4202d53be0f8d9a5fe0/python/triton/language/core.py#L19
|
| 20 |
+
# however, setting limit as 65536 as in LayerNorm tutorial is faster because of less register spilling
|
| 21 |
+
# the optimal maximum block size depends on your hardware, your kernel, and your dtype
|
| 22 |
MAX_FUSED_SIZE = 65536 // 2
|
| 23 |
STATIC_WARPS = 32 if not IS_AMD else 16
|
| 24 |
|
|
|
|
| 42 |
logits += i_n * s_logits
|
| 43 |
target_logits += i_n * s_logits
|
| 44 |
|
| 45 |
+
# running maxima and exponential sums for student and teacher logits.
|
| 46 |
sm = float('-inf')
|
| 47 |
tm = float('-inf')
|
|
|
|
| 48 |
sd, td = 0.0, 0.0
|
| 49 |
|
| 50 |
NV = tl.cdiv(V, BV)
|
| 51 |
for iv in range(0, NV):
|
| 52 |
o_x = iv * BV + tl.arange(0, BV)
|
|
|
|
| 53 |
b_sl = tl.load(logits + o_x, mask=o_x < V, other=float('-inf'))
|
| 54 |
b_sm = tl.max(b_sl)
|
| 55 |
m_new = tl.maximum(sm, b_sm)
|
| 56 |
sd = sd * exp(sm - m_new) + tl.sum(exp(b_sl - m_new))
|
| 57 |
sm = m_new
|
|
|
|
| 58 |
b_tl = tl.load(target_logits + o_x, mask=o_x < V, other=float('-inf'))
|
| 59 |
b_tm = tl.max(b_tl)
|
| 60 |
m_new = tl.maximum(tm, b_tm)
|
|
|
|
| 86 |
|
| 87 |
|
| 88 |
@triton.jit
|
| 89 |
+
def elementwise_mul_kernel(x, g, N: tl.constexpr, B: tl.constexpr):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 90 |
|
|
|
|
| 91 |
i_x = tl.program_id(0).to(tl.int64)
|
| 92 |
o_x = i_x * B + tl.arange(0, B)
|
| 93 |
|
|
|
|
| 94 |
b_g = tl.load(g)
|
| 95 |
+
if b_g == 1.0:
|
| 96 |
+
return
|
| 97 |
b_x = tl.load(x + o_x, mask=o_x < N)
|
| 98 |
tl.store(x + o_x, b_x * b_g, mask=o_x < N)
|
| 99 |
|
| 100 |
|
| 101 |
+
@dispatch
|
| 102 |
+
def fused_kl_div_fwd(
|
| 103 |
x: torch.Tensor,
|
| 104 |
target_x: torch.Tensor,
|
| 105 |
weight: torch.Tensor,
|
| 106 |
target_weight: torch.Tensor,
|
| 107 |
reduction: str = 'batchmean',
|
| 108 |
accumulate_grad_in_fp32: bool = True,
|
| 109 |
+
use_dx: bool = True,
|
| 110 |
+
use_dw: bool = True,
|
| 111 |
):
|
| 112 |
device = x.device
|
| 113 |
|
|
|
|
| 126 |
|
| 127 |
grad_dtype = torch.float32 if accumulate_grad_in_fp32 else weight.dtype
|
| 128 |
|
| 129 |
+
dx = torch.zeros_like(x, device=device) if use_dx else None
|
| 130 |
+
dw = torch.zeros_like(weight, device=device, dtype=grad_dtype) if use_dw else None
|
|
|
|
| 131 |
loss = torch.zeros(N, dtype=torch.float32, device=device)
|
| 132 |
|
| 133 |
for ic in range(NC):
|
|
|
|
| 135 |
# [C, N]
|
| 136 |
c_sx = x[start:end]
|
| 137 |
c_tx = target_x[start:end]
|
|
|
|
| 138 |
# [C, V]
|
| 139 |
c_sl = F.linear(c_sx, weight)
|
| 140 |
c_tl = F.linear(c_tx, target_weight)
|
| 141 |
+
if dw is not None and c_sx.dtype != grad_dtype:
|
| 142 |
c_sx = c_sx.to(dtype=grad_dtype)
|
| 143 |
|
|
|
|
| 144 |
c_loss = loss[start:end]
|
| 145 |
|
| 146 |
# Here we calculate the gradient of c_sx in place so we can save memory.
|
|
|
|
| 164 |
# Thus, we need an additional scaling factor of (n_non_ignore/total) to scale the gradients.
|
| 165 |
# [C, H]
|
| 166 |
|
| 167 |
+
if dx is not None:
|
| 168 |
+
dx[start:end] = torch.mm(c_sl, weight)
|
| 169 |
|
| 170 |
+
if dw is not None:
|
| 171 |
+
torch.addmm(input=dw, mat1=c_sl.t().to(dtype=grad_dtype), mat2=c_sx, out=dw)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 172 |
|
| 173 |
loss = loss.sum()
|
| 174 |
if dw is not None:
|
|
|
|
| 176 |
return loss, dx, dw
|
| 177 |
|
| 178 |
|
| 179 |
+
@dispatch
|
| 180 |
+
def fused_kl_div_bwd(do: torch.Tensor, dx: torch.Tensor | None, dw: torch.Tensor | None):
|
| 181 |
+
# in-place gradient storage across repeated backward calls causes PyTorch anomalies; use Triton.
|
| 182 |
+
for grad in (dx, dw):
|
| 183 |
+
if grad is None:
|
| 184 |
+
continue
|
| 185 |
+
N, H = grad.shape
|
|
|
|
|
|
|
|
|
|
|
|
|
| 186 |
B = min(MAX_FUSED_SIZE, triton.next_power_of_2(H))
|
| 187 |
+
elementwise_mul_kernel[(triton.cdiv(N * H, B),)](x=grad, g=do, N=N*H, B=B, num_warps=STATIC_WARPS,)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 188 |
|
| 189 |
return dx, dw
|
| 190 |
|
|
|
|
| 201 |
target_weight: torch.Tensor,
|
| 202 |
reduction: str,
|
| 203 |
accumulate_grad_in_fp32: bool,
|
| 204 |
+
grad_enabled: bool,
|
| 205 |
):
|
| 206 |
+
loss, dx, dw = fused_kl_div_fwd(
|
| 207 |
x=x,
|
| 208 |
target_x=target_x,
|
| 209 |
weight=weight,
|
| 210 |
target_weight=target_weight,
|
| 211 |
reduction=reduction,
|
| 212 |
accumulate_grad_in_fp32=accumulate_grad_in_fp32,
|
| 213 |
+
use_dx=grad_enabled and ctx.needs_input_grad[0],
|
| 214 |
+
use_dw=grad_enabled and ctx.needs_input_grad[2],
|
| 215 |
)
|
| 216 |
ctx.save_for_backward(dx, dw)
|
| 217 |
return loss
|
|
|
|
| 220 |
@input_guard
|
| 221 |
def backward(ctx, do):
|
| 222 |
dx, dw = ctx.saved_tensors
|
| 223 |
+
dx, dw = fused_kl_div_bwd(do=do, dx=dx, dw=dw)
|
| 224 |
+
return dx, None, dw, None, None, None, None
|
| 225 |
|
| 226 |
|
| 227 |
def fused_kl_div_loss(
|
|
|
|
| 234 |
) -> tuple[torch.Tensor, torch.Tensor]:
|
| 235 |
"""
|
| 236 |
Args:
|
| 237 |
+
x (torch.Tensor):
|
| 238 |
Tensor of shape `[batch_size * seq_len, hidden_size]`.
|
| 239 |
+
target_x (torch.Tensor):
|
| 240 |
Frozen teacher input tensor of shape `[batch_size * seq_len, hidden_size]`.
|
| 241 |
Must not require gradients.
|
| 242 |
+
weight (torch.Tensor):
|
| 243 |
Tensor of shape `[vocab_size, hidden_size]`.
|
| 244 |
+
target_weight (torch.Tensor):
|
| 245 |
Frozen teacher weight tensor of shape `[vocab_size, hidden_size]`.
|
| 246 |
Must not require gradients.
|
| 247 |
+
reduction (str, Optional):
|
| 248 |
Specifies the reduction to apply to the output: 'batchmean'. Default: 'batchmean'.
|
| 249 |
+
accumulate_grad_in_fp32 (bool, Optional):
|
| 250 |
+
Whether to accumulate the student weight gradient in fp32 before casting it back to `weight.dtype`.
|
| 251 |
+
Default: `True`.
|
| 252 |
+
|
| 253 |
Returns:
|
| 254 |
+
loss (torch.Tensor):
|
| 255 |
+
Scalar KL divergence loss.
|
| 256 |
"""
|
| 257 |
if target_x.requires_grad or target_weight.requires_grad:
|
| 258 |
raise RuntimeError(
|
|
|
|
| 267 |
target_weight,
|
| 268 |
reduction,
|
| 269 |
accumulate_grad_in_fp32,
|
| 270 |
+
torch.is_grad_enabled(),
|
| 271 |
)
|
| 272 |
|
| 273 |
|
| 274 |
class FusedKLDivLoss(nn.Module):
|
| 275 |
|
| 276 |
+
def __init__(self, reduction: str = 'batchmean', accumulate_grad_in_fp32: bool = True):
|
|
|
|
|
|
|
|
|
|
|
|
|
| 277 |
"""
|
| 278 |
Args:
|
| 279 |
+
reduction (str, Optional):
|
| 280 |
Specifies the reduction to apply to the output: 'batchmean'. Default: 'batchmean'.
|
| 281 |
+
accumulate_grad_in_fp32 (bool, Optional):
|
| 282 |
+
Whether to accumulate the student weight gradient in fp32 before casting it back to `weight.dtype`.
|
| 283 |
+
Default: `True`.
|
| 284 |
+
|
| 285 |
Note:
|
| 286 |
+
FusedKLDivLoss only computes gradients for `x` and `weight`;
|
| 287 |
+
`target_x` and `target_weight` are treated as frozen teacher tensors and must not require gradients.
|
| 288 |
"""
|
| 289 |
super().__init__()
|
| 290 |
|
|
|
|
| 293 |
self.reduction = reduction
|
| 294 |
self.accumulate_grad_in_fp32 = accumulate_grad_in_fp32
|
| 295 |
|
| 296 |
+
def forward(self, x: torch.Tensor, target_x: torch.Tensor, weight: torch.Tensor, target_weight: torch.Tensor):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 297 |
"""
|
| 298 |
Args:
|
| 299 |
+
x (torch.Tensor):
|
| 300 |
Tensor of shape `[batch_size * seq_len, hidden_size]`.
|
| 301 |
+
target_x (torch.Tensor):
|
| 302 |
Frozen teacher input tensor of shape `[batch_size * seq_len, hidden_size]`.
|
| 303 |
Must not require gradients.
|
| 304 |
+
weight (torch.Tensor):
|
| 305 |
Tensor of shape `[vocab_size, hidden_size]`.
|
| 306 |
+
target_weight (torch.Tensor):
|
| 307 |
Frozen teacher weight tensor of shape `[vocab_size, hidden_size]`.
|
| 308 |
Must not require gradients.
|
| 309 |
+
|
| 310 |
Returns:
|
| 311 |
+
loss (torch.Tensor):
|
| 312 |
+
Scalar KL divergence loss.
|
| 313 |
"""
|
| 314 |
loss = fused_kl_div_loss(
|
| 315 |
x=x,
|
build/torch-cuda/modules/fused_linear_cross_entropy/__init__.py
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright (c) 2023-2026, Songlin Yang, Yu Zhang, Zhiyuan Li
|
| 2 |
+
#
|
| 3 |
+
# This source code is licensed under the MIT license found in the
|
| 4 |
+
# LICENSE file in the root directory of this source tree.
|
| 5 |
+
# For a list of all contributors, visit:
|
| 6 |
+
# https://github.com/fla-org/flash-linear-attention/graphs/contributors
|
| 7 |
+
|
| 8 |
+
from ...modules.fused_linear_cross_entropy.ops import (
|
| 9 |
+
FusedLinearCrossEntropyLoss,
|
| 10 |
+
LinearLossParallel,
|
| 11 |
+
fused_linear_cross_entropy_loss,
|
| 12 |
+
)
|
| 13 |
+
|
| 14 |
+
__all__ = ['FusedLinearCrossEntropyLoss', 'LinearLossParallel', 'fused_linear_cross_entropy_loss']
|
| 15 |
+
|
build/torch-cuda/modules/{fused_linear_cross_entropy.py → fused_linear_cross_entropy/ops.py}
RENAMED
|
@@ -5,10 +5,12 @@
|
|
| 5 |
# For a list of all contributors, visit:
|
| 6 |
# https://github.com/fla-org/flash-linear-attention/graphs/contributors
|
| 7 |
|
| 8 |
-
#
|
| 9 |
-
|
|
|
|
| 10 |
|
| 11 |
from functools import partial
|
|
|
|
| 12 |
|
| 13 |
import torch
|
| 14 |
import torch.nn as nn
|
|
@@ -19,19 +21,23 @@ from torch.distributed import DeviceMesh
|
|
| 19 |
from torch.distributed.tensor import Replicate, Shard, distribute_module
|
| 20 |
from torch.distributed.tensor.parallel import ParallelStyle
|
| 21 |
|
| 22 |
-
from ..
|
| 23 |
-
from ..
|
| 24 |
-
from ..utils import
|
|
|
|
|
|
|
|
|
|
|
|
|
| 25 |
|
| 26 |
try:
|
| 27 |
from torch.distributed.tensor import DTensor
|
| 28 |
except (ImportError, AttributeError):
|
| 29 |
DTensor = None
|
| 30 |
|
| 31 |
-
#
|
| 32 |
# https://github.com/triton-lang/triton/blob/ba42a5c68fd0505f8c42f4202d53be0f8d9a5fe0/python/triton/language/core.py#L19
|
| 33 |
-
#
|
| 34 |
-
#
|
| 35 |
MAX_FUSED_SIZE = 65536 // 2
|
| 36 |
STATIC_WARPS = 32 if not IS_AMD else 16
|
| 37 |
|
|
@@ -42,268 +48,86 @@ STATIC_WARPS = 32 if not IS_AMD else 16
|
|
| 42 |
})
|
| 43 |
@triton.jit
|
| 44 |
def logsumexp_fwd_kernel(
|
| 45 |
-
x,
|
| 46 |
-
z,
|
| 47 |
scale,
|
| 48 |
softcapping,
|
| 49 |
D: tl.constexpr,
|
| 50 |
-
|
| 51 |
HAS_SCALE: tl.constexpr,
|
| 52 |
HAS_SOFTCAPPING: tl.constexpr,
|
| 53 |
):
|
| 54 |
i_n, i_d = tl.program_id(0).to(tl.int64), tl.program_id(1).to(tl.int64)
|
| 55 |
-
o_d = i_d *
|
| 56 |
m_d = o_d < D
|
| 57 |
|
|
|
|
| 58 |
b_x = tl.load(x + i_n * D + o_d, mask=m_d, other=-float('inf'))
|
| 59 |
if HAS_SCALE:
|
| 60 |
b_x = b_x * scale
|
| 61 |
if HAS_SOFTCAPPING:
|
| 62 |
b_x = softcapping * tanh(b_x / softcapping)
|
|
|
|
| 63 |
b_m = tl.max(b_x, 0)
|
| 64 |
b_z = log(tl.sum(exp(b_x - b_m), 0)) + b_m
|
| 65 |
-
tl.store(z + i_n * tl.cdiv(D,
|
| 66 |
|
| 67 |
|
| 68 |
-
@
|
| 69 |
-
def
|
| 70 |
-
x,
|
| 71 |
-
|
| 72 |
-
|
| 73 |
-
|
| 74 |
):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 75 |
shape = x.shape
|
| 76 |
x = x.view(-1, shape[-1])
|
| 77 |
N, D = x.shape
|
| 78 |
-
|
| 79 |
-
ND = triton.cdiv(D,
|
| 80 |
|
| 81 |
z = x.new_empty(N, ND, dtype=torch.float)
|
| 82 |
-
logsumexp_fwd_kernel[(N, ND)](
|
| 83 |
-
x=x,
|
| 84 |
-
z=z,
|
| 85 |
-
scale=scale,
|
| 86 |
-
softcapping=softcapping,
|
| 87 |
-
D=D,
|
| 88 |
-
B=B,
|
| 89 |
-
)
|
| 90 |
z = z.logsumexp(-1).view(*shape[:-1])
|
| 91 |
if dtype is not None and dtype != torch.float:
|
| 92 |
z = z.to(dtype)
|
| 93 |
return z
|
| 94 |
|
| 95 |
|
| 96 |
-
@
|
| 97 |
-
def
|
| 98 |
-
logits,
|
| 99 |
-
lse,
|
| 100 |
-
target,
|
| 101 |
-
loss,
|
| 102 |
-
total,
|
| 103 |
-
ignore_index,
|
| 104 |
-
label_smoothing: tl.constexpr,
|
| 105 |
-
logit_scale: tl.constexpr,
|
| 106 |
-
logit_softcapping: tl.constexpr,
|
| 107 |
-
reduction: tl.constexpr,
|
| 108 |
-
V: tl.constexpr,
|
| 109 |
-
BV: tl.constexpr,
|
| 110 |
-
):
|
| 111 |
-
"""
|
| 112 |
-
This kernel computes both cross entropy loss and the gradient of the input.
|
| 113 |
-
We only consider hard label + mean reduction for now.
|
| 114 |
-
Please refer to https://pytorch.org/docs/stable/generated/torch.nn.CrossEntropyLoss.html for the math.
|
| 115 |
-
|
| 116 |
-
Args:
|
| 117 |
-
logits:
|
| 118 |
-
Pointer to logits tensor.
|
| 119 |
-
lse:
|
| 120 |
-
Pointer to logsumexp tensor.
|
| 121 |
-
target: Pointer to target tensor.
|
| 122 |
-
loss:
|
| 123 |
-
Pointer to tensor to store the loss.
|
| 124 |
-
V (int):
|
| 125 |
-
The number of columns in the input tensor.
|
| 126 |
-
total (int):
|
| 127 |
-
The number of non-ignored classes.
|
| 128 |
-
ignore_index (int):
|
| 129 |
-
The index to ignore in the target.
|
| 130 |
-
label_smoothing (float):
|
| 131 |
-
The amount of smoothing when computing the loss, where 0.0 means no smoothing.
|
| 132 |
-
reduction (str):
|
| 133 |
-
The string for the reduction to apply
|
| 134 |
-
BV (int):
|
| 135 |
-
The block size for vocab.
|
| 136 |
-
"""
|
| 137 |
-
|
| 138 |
-
# https://github.com/triton-lang/triton/issues/1058
|
| 139 |
-
# If B*T*V is too large, i_n * stride will overflow out of int32, so we convert to int64
|
| 140 |
-
i_n = tl.program_id(0).to(tl.int64)
|
| 141 |
-
NV = tl.cdiv(V, BV)
|
| 142 |
-
|
| 143 |
-
# 1. Load target first because if the target is ignore_index, we can return right away
|
| 144 |
-
b_y = tl.load(target + i_n)
|
| 145 |
-
|
| 146 |
-
# 2. locate the start index
|
| 147 |
-
logits += i_n * V
|
| 148 |
-
|
| 149 |
-
if b_y == ignore_index:
|
| 150 |
-
# set all x as 0
|
| 151 |
-
for i in range(0, V, BV):
|
| 152 |
-
o_v = i + tl.arange(0, BV)
|
| 153 |
-
tl.store(logits + o_v, 0.0, mask=o_v < V)
|
| 154 |
-
return
|
| 155 |
-
|
| 156 |
-
# Online softmax: 2 loads + 1 store (compared with 3 loads + 1 store for the safe softmax)
|
| 157 |
-
# Refer to Algorithm 3 in the paper: https://arxiv.org/pdf/1805.02867
|
| 158 |
-
|
| 159 |
-
# 3. [Online softmax] first pass: compute logsumexp
|
| 160 |
-
# we did this in another kernel
|
| 161 |
-
b_l = tl.load(logits + b_y).to(tl.float32) * logit_scale
|
| 162 |
-
if logit_softcapping is not None:
|
| 163 |
-
b_t_y = tanh(b_l / logit_softcapping)
|
| 164 |
-
b_l = logit_softcapping * b_t_y
|
| 165 |
-
# Save the softcap derivative for the target position for use in step 6
|
| 166 |
-
b_softcap_deriv_y = 1.0 - b_t_y * b_t_y
|
| 167 |
-
b_lse = tl.load(lse + i_n)
|
| 168 |
-
|
| 169 |
-
# 4. Calculate the loss
|
| 170 |
-
# loss = lse - logits_l
|
| 171 |
-
b_loss = b_lse - b_l
|
| 172 |
-
|
| 173 |
-
# Label smoothing is a general case of normal cross entropy
|
| 174 |
-
# See the full derivation at https://github.com/linkedin/Liger-Kernel/pull/198#issue-2503665310
|
| 175 |
-
b_z = 0.0
|
| 176 |
-
eps = label_smoothing / V
|
| 177 |
-
|
| 178 |
-
# We need tl.debug_barrier() as mentioned in
|
| 179 |
-
# https://github.com/triton-lang/triton/blob/ba42a5c68fd0505f8c42f4202d53be0f8d9a5fe0/python/triton/ops/cross_entropy.py#L34
|
| 180 |
-
tl.debug_barrier()
|
| 181 |
-
|
| 182 |
-
# 5. [Online Softmax] Second pass: compute gradients
|
| 183 |
-
# For 'mean' reduction, gradients are normalized by number of non-ignored elements
|
| 184 |
-
# dx_y = (softmax(x_y) - 1) / N
|
| 185 |
-
# dx_i = softmax(x_i) / N, i != y
|
| 186 |
-
# For label smoothing:
|
| 187 |
-
# dx_i = (softmax(x_y) - label_smoothing / V) / N, i != y
|
| 188 |
-
# dx_y = (softmax(x_y) - label_smoothing / V - (1 - label_smoothing)) / N
|
| 189 |
-
# = dx_i - (1 - label_smoothing) / N
|
| 190 |
-
for iv in range(0, NV):
|
| 191 |
-
o_v = iv * BV + tl.arange(0, BV)
|
| 192 |
-
b_logits = tl.load(logits + o_v, mask=o_v < V, other=float('-inf')).to(tl.float32) * logit_scale
|
| 193 |
-
if logit_softcapping is not None:
|
| 194 |
-
b_t = tanh(b_logits / logit_softcapping)
|
| 195 |
-
b_capped = logit_softcapping * b_t
|
| 196 |
-
else:
|
| 197 |
-
b_capped = b_logits
|
| 198 |
-
if label_smoothing > 0:
|
| 199 |
-
# scale X beforehand to avoid overflow
|
| 200 |
-
b_z += tl.sum(tl.where(o_v < V, -eps * b_capped, 0.0))
|
| 201 |
-
b_p = (exp(b_capped - b_lse) - eps) * logit_scale
|
| 202 |
-
# d(softcap * tanh(x/softcap))/dx = 1 - tanh(x/softcap)^2
|
| 203 |
-
if logit_softcapping is not None:
|
| 204 |
-
b_p = b_p * (1.0 - b_t * b_t)
|
| 205 |
-
if reduction == "mean":
|
| 206 |
-
b_p = b_p / total
|
| 207 |
-
tl.store(logits + o_v, b_p, mask=o_v < V)
|
| 208 |
-
|
| 209 |
-
tl.debug_barrier()
|
| 210 |
-
|
| 211 |
-
# Original loss = H(q, p), with label smoothing regularization = H(q', p) and (label_smoothing / V) = eps
|
| 212 |
-
# H(q', p) = (1 - label_smoothing) * H(q, p) + label_smoothing * H(u, p)
|
| 213 |
-
# = (1 - label_smoothing) * H(q, p) + eps * sum(logsoftmax(x_i))
|
| 214 |
-
# By using m (global max of xi) and d (sum of e^(xi-m)), we can simplify as:
|
| 215 |
-
# = (1 - label_smoothing) * H(q, p) + (-sum(x_i * eps) + label_smoothing * (m + logd))
|
| 216 |
-
# Refer to H(q', p) in section 7 of the paper:
|
| 217 |
-
# https://arxiv.org/pdf/1512.00567
|
| 218 |
-
# pytorch:
|
| 219 |
-
# https://github.com/pytorch/pytorch/blob/2981534f54d49fa3a9755c9b0855e7929c2527f0/aten/src/ATen/native/LossNLL.cpp#L516
|
| 220 |
-
# See full derivation at https://github.com/linkedin/Liger-Kernel/pull/198#issuecomment-2333753087
|
| 221 |
-
if label_smoothing > 0:
|
| 222 |
-
b_loss = b_loss * (1 - label_smoothing) + (b_z + label_smoothing * b_lse)
|
| 223 |
-
|
| 224 |
-
# 6. Specially handle the i==y case where `dx_y = (softmax(x_y) - (1 - label_smoothing) / N`
|
| 225 |
-
b_l = tl.load(logits + b_y)
|
| 226 |
-
|
| 227 |
-
# The correction term also needs the softcap chain rule factor
|
| 228 |
-
if logit_softcapping is not None:
|
| 229 |
-
b_sc_factor = b_softcap_deriv_y
|
| 230 |
-
else:
|
| 231 |
-
b_sc_factor = 1.0
|
| 232 |
-
|
| 233 |
-
# Normalize the loss by the number of non-ignored elements if reduction is "mean"
|
| 234 |
-
if reduction == 'mean':
|
| 235 |
-
b_loss = b_loss / total
|
| 236 |
-
b_l += (label_smoothing - 1) / total * logit_scale * b_sc_factor
|
| 237 |
-
else:
|
| 238 |
-
b_l += (label_smoothing - 1) * logit_scale * b_sc_factor
|
| 239 |
-
|
| 240 |
-
tl.store(loss + i_n, b_loss)
|
| 241 |
-
tl.store(logits + b_y, b_l)
|
| 242 |
-
|
| 243 |
-
|
| 244 |
-
@triton.jit
|
| 245 |
-
def elementwise_mul_kernel(
|
| 246 |
-
x,
|
| 247 |
-
g,
|
| 248 |
-
N: tl.constexpr,
|
| 249 |
-
B: tl.constexpr,
|
| 250 |
-
):
|
| 251 |
-
"""
|
| 252 |
-
This function multiplies each element of the tensor pointed by x with the value pointed by g.
|
| 253 |
-
The multiplication is performed in-place on the tensor pointed by x.
|
| 254 |
-
|
| 255 |
-
Parameters:
|
| 256 |
-
x:
|
| 257 |
-
Pointer to the input tensor.
|
| 258 |
-
g:
|
| 259 |
-
Pointer to the gradient output value.
|
| 260 |
-
N (int):
|
| 261 |
-
The number of columns in the input tensor.
|
| 262 |
-
B (int):
|
| 263 |
-
The block size for Triton operations.
|
| 264 |
-
"""
|
| 265 |
-
|
| 266 |
-
# Get the program ID and convert it to int64 to avoid overflow
|
| 267 |
-
i_x = tl.program_id(0).to(tl.int64)
|
| 268 |
-
o_x = i_x * B + tl.arange(0, B)
|
| 269 |
-
|
| 270 |
-
# Load the gradient output value
|
| 271 |
-
b_g = tl.load(g)
|
| 272 |
-
b_x = tl.load(x + o_x, mask=o_x < N)
|
| 273 |
-
tl.store(x + o_x, b_x * b_g, mask=o_x < N)
|
| 274 |
-
|
| 275 |
-
|
| 276 |
-
@dispatch('modules')
|
| 277 |
-
def fused_linear_cross_entropy_forward(
|
| 278 |
x: torch.Tensor,
|
| 279 |
target: torch.LongTensor,
|
| 280 |
weight: torch.Tensor,
|
| 281 |
-
bias: torch.Tensor = None,
|
| 282 |
ignore_index: int = -100,
|
| 283 |
label_smoothing: float = 0.0,
|
| 284 |
logit_scale: float = 1.0,
|
| 285 |
-
logit_softcapping: float = None,
|
| 286 |
num_chunks: int = 8,
|
| 287 |
reduction: str = "mean",
|
| 288 |
use_l2warp: bool = False,
|
| 289 |
l2_penalty_factor: float = 1e-4,
|
| 290 |
accumulate_grad_in_fp32: bool = True,
|
|
|
|
| 291 |
):
|
| 292 |
device = x.device
|
| 293 |
-
|
| 294 |
-
#
|
| 295 |
-
# the increase in memory = [N, V]
|
| 296 |
-
# reduction can be achieved by partitioning the number of tokens N into smaller chunks.
|
| 297 |
-
|
| 298 |
-
# ideally, we would like to achieve the same memory consumption as [N, H],
|
| 299 |
-
# so the expected chunk size should be:
|
| 300 |
-
# NC = ceil(V / H)
|
| 301 |
-
# C = ceil(N / NC)
|
| 302 |
-
# for ex: N = 4096*4, V = 32000, H = 4096 ==> NC = 8, C = ceil(N / NC) = 2048
|
| 303 |
N, H, V = *x.shape, weight.shape[0]
|
| 304 |
-
BV = min(MAX_FUSED_SIZE, triton.next_power_of_2(V))
|
| 305 |
-
# TODO: in real cases, we may need to limit the number of chunks NC to
|
| 306 |
-
# ensure the precisions of accumulated gradients
|
| 307 |
NC = min(num_chunks, triton.cdiv(V, H))
|
| 308 |
C = triton.next_power_of_2(triton.cdiv(N, NC))
|
| 309 |
NC = triton.cdiv(N, C)
|
|
@@ -322,87 +146,83 @@ def fused_linear_cross_entropy_forward(
|
|
| 322 |
# [N]
|
| 323 |
loss = torch.zeros(N, device=device, dtype=torch.float)
|
| 324 |
|
| 325 |
-
total = target.ne(ignore_index).sum().
|
|
|
|
| 326 |
|
| 327 |
for ic in range(NC):
|
| 328 |
start, end = ic * C, min((ic + 1) * C, N)
|
| 329 |
-
# [C,
|
| 330 |
c_x = x[start:end]
|
| 331 |
-
# when doing matmul, use the original precision
|
| 332 |
# [C, V]
|
| 333 |
c_logits = F.linear(c_x, weight, bias)
|
| 334 |
if weight is not None and c_x.dtype != grad_dtype:
|
| 335 |
c_x = c_x.to(dtype=grad_dtype)
|
| 336 |
c_target = target[start:end]
|
| 337 |
-
|
| 338 |
-
|
| 339 |
-
|
| 340 |
-
|
| 341 |
-
|
| 342 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 343 |
if use_l2warp:
|
| 344 |
c_maxx, c_ids = torch.max(c_logits, -1, keepdim=True)
|
| 345 |
-
|
| 346 |
-
|
| 347 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 348 |
logits=c_logits,
|
| 349 |
-
lse=c_lse,
|
| 350 |
target=c_target,
|
| 351 |
-
|
| 352 |
-
|
| 353 |
-
ignore_index=ignore_index,
|
| 354 |
label_smoothing=label_smoothing,
|
| 355 |
logit_scale=logit_scale,
|
| 356 |
logit_softcapping=logit_softcapping,
|
| 357 |
-
|
| 358 |
-
|
| 359 |
-
|
| 360 |
-
|
| 361 |
)
|
| 362 |
if use_l2warp:
|
| 363 |
-
# a. Calculate the L2 gradient w.r.t logits (g_logits_l2)
|
| 364 |
g_logits_l2 = torch.zeros_like(c_logits)
|
| 365 |
|
| 366 |
-
#
|
| 367 |
l2_factor = l2_penalty_factor / N
|
| 368 |
penalty_grad = c_maxx * l2_factor
|
| 369 |
g_logits_l2.scatter_(-1, c_ids, penalty_grad)
|
| 370 |
|
| 371 |
-
# b. Backpropagate g_logits_l2 to get its effect on dx, dw, db
|
| 372 |
-
# and add it to the main gradients.
|
| 373 |
-
# Total_dx = CE_dx + L2_dx
|
| 374 |
-
# Total_dw = CE_dw + L2_dw
|
| 375 |
-
# Total_db = CE_db + L2_db
|
| 376 |
if weight is not None:
|
| 377 |
-
torch.addmm(
|
| 378 |
-
input=dw,
|
| 379 |
-
mat1=g_logits_l2.t().to(dtype=grad_dtype),
|
| 380 |
-
mat2=c_x,
|
| 381 |
-
out=dw,
|
| 382 |
-
)
|
| 383 |
if bias is not None:
|
| 384 |
torch.add(input=db, other=g_logits_l2.sum(0, dtype=bias_grad_dtype), out=db)
|
| 385 |
-
#
|
| 386 |
dx_l2_contribution = torch.mm(g_logits_l2, weight)
|
| 387 |
else:
|
| 388 |
dx_l2_contribution = 0.0
|
| 389 |
|
| 390 |
-
# gradient of logits is computed in-place by the above triton kernel and is of shape: C x V
|
| 391 |
-
# thus dx should be of shape: C x H
|
| 392 |
dx[start:end] = torch.mm(c_logits, weight) + dx_l2_contribution
|
| 393 |
|
| 394 |
if weight is not None:
|
| 395 |
-
torch.addmm(
|
| 396 |
-
input=dw,
|
| 397 |
-
mat1=c_logits.t().to(dtype=grad_dtype),
|
| 398 |
-
mat2=c_x,
|
| 399 |
-
out=dw,
|
| 400 |
-
)
|
| 401 |
|
| 402 |
if bias is not None:
|
| 403 |
torch.add(input=db, other=c_logits.sum(0, dtype=bias_grad_dtype), out=db)
|
| 404 |
|
|
|
|
|
|
|
| 405 |
loss = loss.sum()
|
|
|
|
|
|
|
| 406 |
if dw is not None:
|
| 407 |
dw = dw.to(weight)
|
| 408 |
if db is not None:
|
|
@@ -410,51 +230,30 @@ def fused_linear_cross_entropy_forward(
|
|
| 410 |
return loss, dx, dw, db
|
| 411 |
|
| 412 |
|
| 413 |
-
@dispatch
|
| 414 |
-
def
|
| 415 |
-
|
| 416 |
-
|
| 417 |
-
|
| 418 |
-
|
| 419 |
-
)
|
| 420 |
-
# If cross entropy is the last layer, do is 1.0. Skip the mul to save time
|
| 421 |
-
if torch.ne(do, torch.tensor(1.0, device=do.device)):
|
| 422 |
-
# We use a Triton kernel instead of a PyTorch operation because modifying inputs in-place
|
| 423 |
-
# for gradient storage and backward multiple times causes anomalies with PyTorch but not with Triton.
|
| 424 |
-
N, H = dx.shape
|
| 425 |
-
B = min(MAX_FUSED_SIZE, triton.next_power_of_2(H))
|
| 426 |
-
|
| 427 |
-
elementwise_mul_kernel[(triton.cdiv(N * H, B),)](
|
| 428 |
-
x=dx,
|
| 429 |
-
g=do,
|
| 430 |
-
N=N*H,
|
| 431 |
-
B=B,
|
| 432 |
-
num_warps=STATIC_WARPS,
|
| 433 |
-
)
|
| 434 |
|
| 435 |
-
|
| 436 |
-
|
| 437 |
-
|
| 438 |
-
|
| 439 |
-
|
| 440 |
-
|
| 441 |
-
|
| 442 |
-
B=B,
|
| 443 |
-
num_warps=STATIC_WARPS,
|
| 444 |
-
)
|
| 445 |
-
|
| 446 |
-
if db is not None:
|
| 447 |
-
V = db.shape[0]
|
| 448 |
-
elementwise_mul_kernel[(triton.cdiv(V, B),)](
|
| 449 |
-
x=db,
|
| 450 |
-
g=do,
|
| 451 |
-
N=V,
|
| 452 |
-
B=B,
|
| 453 |
-
num_warps=STATIC_WARPS,
|
| 454 |
-
)
|
| 455 |
return dx, dw, db
|
| 456 |
|
| 457 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 458 |
class FusedLinearCrossEntropyFunction(torch.autograd.Function):
|
| 459 |
|
| 460 |
@staticmethod
|
|
@@ -464,76 +263,35 @@ class FusedLinearCrossEntropyFunction(torch.autograd.Function):
|
|
| 464 |
x: torch.Tensor,
|
| 465 |
target: torch.LongTensor,
|
| 466 |
weight: torch.Tensor,
|
| 467 |
-
bias: torch.Tensor = None,
|
| 468 |
ignore_index: int = -100,
|
| 469 |
label_smoothing: float = 0.0,
|
| 470 |
logit_scale: float = 1.0,
|
| 471 |
-
logit_softcapping: float = None,
|
| 472 |
num_chunks: int = 8,
|
| 473 |
reduction: str = "mean",
|
| 474 |
use_l2warp: bool = False,
|
| 475 |
l2_penalty_factor: float = 1e-4,
|
| 476 |
accumulate_grad_in_fp32: bool = True,
|
|
|
|
| 477 |
):
|
| 478 |
-
"""
|
| 479 |
-
|
| 480 |
-
|
| 481 |
-
|
| 482 |
-
|
| 483 |
-
|
| 484 |
-
|
| 485 |
-
|
| 486 |
-
|
| 487 |
-
|
| 488 |
-
|
| 489 |
-
|
| 490 |
-
|
| 491 |
-
|
| 492 |
-
|
| 493 |
-
|
| 494 |
-
ignore_index:
|
| 495 |
-
the index to ignore in the target.
|
| 496 |
-
label_smoothing:
|
| 497 |
-
the amount of smoothing when computing the loss, where 0.0 means no smoothing.
|
| 498 |
-
logit_scale: float = 1.0,
|
| 499 |
-
A scaling factor applied to the logits. Default: 1.0
|
| 500 |
-
logit_softcapping: float = None,
|
| 501 |
-
If > 0, apply logit softcapping: logits = softcap * tanh(logits / softcap).
|
| 502 |
-
Default: 0.0
|
| 503 |
-
num_chunks: int
|
| 504 |
-
The number of chunks to split the input tensor into for processing.
|
| 505 |
-
This can help optimize memory usage and computation speed.
|
| 506 |
-
Default: 8
|
| 507 |
-
reduction:
|
| 508 |
-
Specifies the reduction to apply to the output: 'mean' | 'sum'.
|
| 509 |
-
'mean': the weighted mean of the output is taken,
|
| 510 |
-
'sum': the output will be summed.
|
| 511 |
-
Default: 'mean'.
|
| 512 |
-
use_l2warp: bool = False,
|
| 513 |
-
Whether to use L2 regularization on the logits to prevent overconfidence.
|
| 514 |
-
Default: False
|
| 515 |
-
l2_penalty_factor: float = 1e-4,
|
| 516 |
-
The L2Warp penalty factor. Default: 1e-4
|
| 517 |
-
accumulate_grad_in_fp32: bool = True,
|
| 518 |
-
Whether to accumulate weight and bias gradients in fp32 before casting them
|
| 519 |
-
back to the parameter dtype. Default: True
|
| 520 |
-
"""
|
| 521 |
-
loss, dx, dw, db = fused_linear_cross_entropy_forward(
|
| 522 |
-
x,
|
| 523 |
-
target,
|
| 524 |
-
weight,
|
| 525 |
-
bias,
|
| 526 |
-
ignore_index,
|
| 527 |
-
label_smoothing,
|
| 528 |
-
logit_scale,
|
| 529 |
-
logit_softcapping,
|
| 530 |
-
num_chunks,
|
| 531 |
-
reduction,
|
| 532 |
-
use_l2warp,
|
| 533 |
-
l2_penalty_factor,
|
| 534 |
-
accumulate_grad_in_fp32,
|
| 535 |
)
|
| 536 |
-
# downcast to dtype and store for backward
|
| 537 |
ctx.save_for_backward(
|
| 538 |
dx.detach(),
|
| 539 |
dw.detach() if weight is not None else None,
|
|
@@ -545,62 +303,71 @@ class FusedLinearCrossEntropyFunction(torch.autograd.Function):
|
|
| 545 |
@input_guard
|
| 546 |
def backward(ctx, do):
|
| 547 |
dx, dw, db = ctx.saved_tensors
|
| 548 |
-
dx, dw, db =
|
| 549 |
-
return dx, None, dw, db, None, None, None, None, None, None, None, None, None
|
| 550 |
|
| 551 |
|
| 552 |
def fused_linear_cross_entropy_loss(
|
| 553 |
x: torch.Tensor,
|
| 554 |
target: torch.LongTensor,
|
| 555 |
weight: torch.Tensor,
|
| 556 |
-
bias: torch.Tensor = None,
|
| 557 |
ignore_index: int = -100,
|
| 558 |
label_smoothing: float = 0.0,
|
| 559 |
logit_scale: float = 1.0,
|
| 560 |
-
logit_softcapping: float = None,
|
| 561 |
num_chunks: int = 8,
|
| 562 |
reduction: str = "mean",
|
| 563 |
use_l2warp: bool = False,
|
| 564 |
l2_penalty_factor: float = 1e-4,
|
| 565 |
accumulate_grad_in_fp32: bool = True,
|
| 566 |
-
|
|
|
|
| 567 |
"""
|
| 568 |
Args:
|
| 569 |
-
x (torch.Tensor):
|
| 570 |
-
|
| 571 |
-
|
| 572 |
-
|
| 573 |
-
|
| 574 |
-
|
| 575 |
-
|
| 576 |
-
|
| 577 |
-
|
| 578 |
-
|
| 579 |
-
|
| 580 |
-
|
| 581 |
-
|
| 582 |
-
|
| 583 |
-
|
| 584 |
-
|
|
|
|
|
|
|
| 585 |
The number of chunks to split the input tensor into for processing.
|
| 586 |
This can help optimize memory usage and computation speed.
|
| 587 |
-
Default: 8
|
| 588 |
-
reduction:
|
| 589 |
Specifies the reduction to apply to the output: 'mean' | 'sum'.
|
| 590 |
'mean': the weighted mean of the output is taken,
|
| 591 |
'sum': the output will be summed.
|
| 592 |
Default: 'mean'.
|
| 593 |
-
use_l2warp:
|
| 594 |
-
Whether to add the L2Warp logit regularization gradient.
|
| 595 |
-
the full number of input tokens, matching `fla.modules.l2warp.l2_warp`.
|
| 596 |
Default: `False`.
|
| 597 |
-
l2_penalty_factor:
|
| 598 |
The L2Warp penalty factor. Default: `1e-4`.
|
| 599 |
-
accumulate_grad_in_fp32:
|
| 600 |
-
Whether to accumulate weight and bias gradients in fp32 before casting them
|
| 601 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 602 |
Returns:
|
| 603 |
-
|
|
|
|
| 604 |
"""
|
| 605 |
return FusedLinearCrossEntropyFunction.apply(
|
| 606 |
x,
|
|
@@ -616,6 +383,7 @@ def fused_linear_cross_entropy_loss(
|
|
| 616 |
use_l2warp,
|
| 617 |
l2_penalty_factor,
|
| 618 |
accumulate_grad_in_fp32,
|
|
|
|
| 619 |
)
|
| 620 |
|
| 621 |
|
|
@@ -626,41 +394,47 @@ class FusedLinearCrossEntropyLoss(nn.Module):
|
|
| 626 |
ignore_index: int = -100,
|
| 627 |
label_smoothing: float = 0.0,
|
| 628 |
logit_scale: float = 1.0,
|
| 629 |
-
logit_softcapping: float = None,
|
| 630 |
num_chunks: int = 8,
|
| 631 |
reduction: str = "mean",
|
| 632 |
use_l2warp: bool = False,
|
| 633 |
l2_penalty_factor: float = 1e-4,
|
| 634 |
accumulate_grad_in_fp32: bool = True,
|
|
|
|
| 635 |
):
|
| 636 |
"""
|
| 637 |
Args:
|
| 638 |
-
ignore_index
|
| 639 |
-
|
| 640 |
-
label_smoothing
|
| 641 |
-
|
| 642 |
-
|
| 643 |
-
|
| 644 |
-
|
| 645 |
-
|
| 646 |
-
|
|
|
|
| 647 |
The number of chunks to split the input tensor into for processing.
|
| 648 |
This can help optimize memory usage and computation speed.
|
| 649 |
-
Default: 8
|
| 650 |
-
reduction:
|
| 651 |
Specifies the reduction to apply to the output: 'mean' | 'sum'.
|
| 652 |
'mean': the weighted mean of the output is taken,
|
| 653 |
'sum': the output will be summed.
|
| 654 |
Default: 'mean'.
|
| 655 |
-
use_l2warp:
|
| 656 |
-
Whether to add the L2Warp logit regularization gradient.
|
| 657 |
-
the full number of input tokens, matching `fla.modules.l2warp.l2_warp`.
|
| 658 |
Default: `False`.
|
| 659 |
-
l2_penalty_factor:
|
| 660 |
The L2Warp penalty factor. Default: `1e-4`.
|
| 661 |
-
accumulate_grad_in_fp32:
|
| 662 |
-
Whether to accumulate weight and bias gradients in fp32 before casting them
|
| 663 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 664 |
"""
|
| 665 |
super().__init__()
|
| 666 |
|
|
@@ -675,30 +449,28 @@ class FusedLinearCrossEntropyLoss(nn.Module):
|
|
| 675 |
self.use_l2warp = use_l2warp
|
| 676 |
self.l2_penalty_factor = l2_penalty_factor
|
| 677 |
self.accumulate_grad_in_fp32 = accumulate_grad_in_fp32
|
|
|
|
| 678 |
|
| 679 |
@torch.compiler.disable
|
| 680 |
-
def forward(
|
| 681 |
-
self,
|
| 682 |
-
x: torch.Tensor,
|
| 683 |
-
target: torch.LongTensor,
|
| 684 |
-
weight: torch.Tensor,
|
| 685 |
-
bias: torch.Tensor | None = None,
|
| 686 |
-
):
|
| 687 |
"""
|
| 688 |
Args:
|
| 689 |
-
x (torch.Tensor):
|
| 690 |
-
|
| 691 |
-
|
| 692 |
-
|
| 693 |
-
|
| 694 |
-
|
| 695 |
-
|
|
|
|
|
|
|
| 696 |
Returns:
|
| 697 |
-
|
|
|
|
| 698 |
"""
|
| 699 |
loss = fused_linear_cross_entropy_loss(
|
| 700 |
-
x.
|
| 701 |
-
target.
|
| 702 |
weight=weight,
|
| 703 |
bias=bias,
|
| 704 |
ignore_index=self.ignore_index,
|
|
@@ -710,17 +482,13 @@ class FusedLinearCrossEntropyLoss(nn.Module):
|
|
| 710 |
use_l2warp=self.use_l2warp,
|
| 711 |
l2_penalty_factor=self.l2_penalty_factor,
|
| 712 |
accumulate_grad_in_fp32=self.accumulate_grad_in_fp32,
|
|
|
|
| 713 |
)
|
| 714 |
return loss
|
| 715 |
|
| 716 |
|
| 717 |
class LinearLossParallel(ParallelStyle):
|
| 718 |
-
def __init__(
|
| 719 |
-
self,
|
| 720 |
-
*,
|
| 721 |
-
sequence_dim: int = 1,
|
| 722 |
-
use_local_output: bool = False,
|
| 723 |
-
):
|
| 724 |
super().__init__()
|
| 725 |
|
| 726 |
self.sequence_sharding = (Shard(sequence_dim),)
|
|
@@ -755,7 +523,7 @@ class LinearLossParallel(ParallelStyle):
|
|
| 755 |
|
| 756 |
@staticmethod
|
| 757 |
def _prepare_output_fn(use_local_output, mod, outputs, device_mesh):
|
| 758 |
-
return outputs.to_local() if use_local_output else outputs
|
| 759 |
|
| 760 |
def _apply(self, module: nn.Module, device_mesh: DeviceMesh) -> nn.Module:
|
| 761 |
return distribute_module(
|
|
|
|
| 5 |
# For a list of all contributors, visit:
|
| 6 |
# https://github.com/fla-org/flash-linear-attention/graphs/contributors
|
| 7 |
|
| 8 |
+
# adapted from https://github.com/linkedin/Liger-Kernel/blob/main/src/liger_kernel/ops/fused_linear_cross_entropy.py
|
| 9 |
+
|
| 10 |
+
from __future__ import annotations
|
| 11 |
|
| 12 |
from functools import partial
|
| 13 |
+
from typing import TYPE_CHECKING
|
| 14 |
|
| 15 |
import torch
|
| 16 |
import torch.nn as nn
|
|
|
|
| 21 |
from torch.distributed.tensor import Replicate, Shard, distribute_module
|
| 22 |
from torch.distributed.tensor.parallel import ParallelStyle
|
| 23 |
|
| 24 |
+
from ...backends import dispatch
|
| 25 |
+
from ...modules.fused_cross_entropy.ops import cross_entropy_bwd, cross_entropy_fwd
|
| 26 |
+
from ...ops.utils.op import exp, log, tanh
|
| 27 |
+
from ...utils import IS_AMD, input_guard
|
| 28 |
+
|
| 29 |
+
if TYPE_CHECKING:
|
| 30 |
+
from torch.distributed import ProcessGroup
|
| 31 |
|
| 32 |
try:
|
| 33 |
from torch.distributed.tensor import DTensor
|
| 34 |
except (ImportError, AttributeError):
|
| 35 |
DTensor = None
|
| 36 |
|
| 37 |
+
# the hard limit of TRITON_MAX_TENSOR_NUMEL is 1048576
|
| 38 |
# https://github.com/triton-lang/triton/blob/ba42a5c68fd0505f8c42f4202d53be0f8d9a5fe0/python/triton/language/core.py#L19
|
| 39 |
+
# however, setting limit as 65536 as in LayerNorm tutorial is faster because of less register spilling
|
| 40 |
+
# the optimal maximum block size depends on your hardware, your kernel, and your dtype
|
| 41 |
MAX_FUSED_SIZE = 65536 // 2
|
| 42 |
STATIC_WARPS = 32 if not IS_AMD else 16
|
| 43 |
|
|
|
|
| 48 |
})
|
| 49 |
@triton.jit
|
| 50 |
def logsumexp_fwd_kernel(
|
| 51 |
+
x, # [N, D]
|
| 52 |
+
z, # [N, ND]
|
| 53 |
scale,
|
| 54 |
softcapping,
|
| 55 |
D: tl.constexpr,
|
| 56 |
+
BD: tl.constexpr,
|
| 57 |
HAS_SCALE: tl.constexpr,
|
| 58 |
HAS_SOFTCAPPING: tl.constexpr,
|
| 59 |
):
|
| 60 |
i_n, i_d = tl.program_id(0).to(tl.int64), tl.program_id(1).to(tl.int64)
|
| 61 |
+
o_d = i_d * BD + tl.arange(0, BD)
|
| 62 |
m_d = o_d < D
|
| 63 |
|
| 64 |
+
# [BD]
|
| 65 |
b_x = tl.load(x + i_n * D + o_d, mask=m_d, other=-float('inf'))
|
| 66 |
if HAS_SCALE:
|
| 67 |
b_x = b_x * scale
|
| 68 |
if HAS_SOFTCAPPING:
|
| 69 |
b_x = softcapping * tanh(b_x / softcapping)
|
| 70 |
+
b_x = tl.where(m_d, b_x, -float('inf'))
|
| 71 |
b_m = tl.max(b_x, 0)
|
| 72 |
b_z = log(tl.sum(exp(b_x - b_m), 0)) + b_m
|
| 73 |
+
tl.store(z + i_n * tl.cdiv(D, BD) + i_d, b_z)
|
| 74 |
|
| 75 |
|
| 76 |
+
@triton.jit
|
| 77 |
+
def elementwise_mul_kernel(
|
| 78 |
+
x, # [N]
|
| 79 |
+
g, # scalar
|
| 80 |
+
N: tl.constexpr,
|
| 81 |
+
BN: tl.constexpr,
|
| 82 |
):
|
| 83 |
+
i_x = tl.program_id(0).to(tl.int64)
|
| 84 |
+
o_x = i_x * BN + tl.arange(0, BN)
|
| 85 |
+
|
| 86 |
+
b_g = tl.load(g)
|
| 87 |
+
if b_g == 1.0:
|
| 88 |
+
return
|
| 89 |
+
# [BN]
|
| 90 |
+
b_x = tl.load(x + o_x, mask=o_x < N)
|
| 91 |
+
tl.store(x + o_x, b_x * b_g, mask=o_x < N)
|
| 92 |
+
|
| 93 |
+
|
| 94 |
+
@dispatch
|
| 95 |
+
def logsumexp_fwd(x, scale: float | None = None, softcapping: float | None = None, dtype: torch.dtype | None = None):
|
| 96 |
shape = x.shape
|
| 97 |
x = x.view(-1, shape[-1])
|
| 98 |
N, D = x.shape
|
| 99 |
+
BD = min(triton.next_power_of_2(D), 64 * 1024)
|
| 100 |
+
ND = triton.cdiv(D, BD)
|
| 101 |
|
| 102 |
z = x.new_empty(N, ND, dtype=torch.float)
|
| 103 |
+
logsumexp_fwd_kernel[(N, ND)](x=x, z=z, scale=scale, softcapping=softcapping, D=D, BD=BD)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 104 |
z = z.logsumexp(-1).view(*shape[:-1])
|
| 105 |
if dtype is not None and dtype != torch.float:
|
| 106 |
z = z.to(dtype)
|
| 107 |
return z
|
| 108 |
|
| 109 |
|
| 110 |
+
@dispatch
|
| 111 |
+
def fused_linear_cross_entropy_fwd(
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 112 |
x: torch.Tensor,
|
| 113 |
target: torch.LongTensor,
|
| 114 |
weight: torch.Tensor,
|
| 115 |
+
bias: torch.Tensor | None = None,
|
| 116 |
ignore_index: int = -100,
|
| 117 |
label_smoothing: float = 0.0,
|
| 118 |
logit_scale: float = 1.0,
|
| 119 |
+
logit_softcapping: float | None = None,
|
| 120 |
num_chunks: int = 8,
|
| 121 |
reduction: str = "mean",
|
| 122 |
use_l2warp: bool = False,
|
| 123 |
l2_penalty_factor: float = 1e-4,
|
| 124 |
accumulate_grad_in_fp32: bool = True,
|
| 125 |
+
process_group: ProcessGroup | None = None,
|
| 126 |
):
|
| 127 |
device = x.device
|
| 128 |
+
world_size = 1 if process_group is None else torch.distributed.get_world_size(process_group)
|
| 129 |
+
# chunking keeps temporary logits storage close to the input tensor size.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 130 |
N, H, V = *x.shape, weight.shape[0]
|
|
|
|
|
|
|
|
|
|
| 131 |
NC = min(num_chunks, triton.cdiv(V, H))
|
| 132 |
C = triton.next_power_of_2(triton.cdiv(N, NC))
|
| 133 |
NC = triton.cdiv(N, C)
|
|
|
|
| 146 |
# [N]
|
| 147 |
loss = torch.zeros(N, device=device, dtype=torch.float)
|
| 148 |
|
| 149 |
+
total = target.ne(ignore_index).sum().clamp_min(1)
|
| 150 |
+
dloss = total.float().reciprocal() if reduction == "mean" else x.new_ones((), dtype=torch.float)
|
| 151 |
|
| 152 |
for ic in range(NC):
|
| 153 |
start, end = ic * C, min((ic + 1) * C, N)
|
| 154 |
+
# [C, H]
|
| 155 |
c_x = x[start:end]
|
|
|
|
| 156 |
# [C, V]
|
| 157 |
c_logits = F.linear(c_x, weight, bias)
|
| 158 |
if weight is not None and c_x.dtype != grad_dtype:
|
| 159 |
c_x = c_x.to(dtype=grad_dtype)
|
| 160 |
c_target = target[start:end]
|
| 161 |
+
c_loss, _, c_lse, total_classes, class_start_idx = cross_entropy_fwd(
|
| 162 |
+
logits=c_logits,
|
| 163 |
+
target=c_target,
|
| 164 |
+
label_smoothing=label_smoothing,
|
| 165 |
+
logit_scale=logit_scale,
|
| 166 |
+
logit_softcapping=logit_softcapping,
|
| 167 |
+
ignore_index=ignore_index,
|
| 168 |
+
process_group=process_group,
|
| 169 |
+
)
|
| 170 |
+
loss[start:end] = c_loss
|
| 171 |
if use_l2warp:
|
| 172 |
c_maxx, c_ids = torch.max(c_logits, -1, keepdim=True)
|
| 173 |
+
if world_size > 1:
|
| 174 |
+
# only the shard owning the first global maximum contributes the L2 gradient
|
| 175 |
+
local_max = c_maxx.clone()
|
| 176 |
+
torch.distributed.all_reduce(c_maxx, op=torch.distributed.ReduceOp.MAX, group=process_group)
|
| 177 |
+
c_ids = torch.where(local_max == c_maxx, c_ids + class_start_idx, total_classes)
|
| 178 |
+
torch.distributed.all_reduce(c_ids, op=torch.distributed.ReduceOp.MIN, group=process_group)
|
| 179 |
+
c_ids -= class_start_idx
|
| 180 |
+
c_maxx = torch.where((c_ids >= 0) & (c_ids < V), c_maxx, 0)
|
| 181 |
+
c_ids = c_ids.clamp(0, V - 1)
|
| 182 |
+
|
| 183 |
+
cross_entropy_bwd(
|
| 184 |
logits=c_logits,
|
|
|
|
| 185 |
target=c_target,
|
| 186 |
+
lse=c_lse,
|
| 187 |
+
dloss=dloss.expand(end - start),
|
|
|
|
| 188 |
label_smoothing=label_smoothing,
|
| 189 |
logit_scale=logit_scale,
|
| 190 |
logit_softcapping=logit_softcapping,
|
| 191 |
+
ignore_index=ignore_index,
|
| 192 |
+
total_classes=total_classes,
|
| 193 |
+
class_start_idx=class_start_idx,
|
| 194 |
+
inplace_backward=True,
|
| 195 |
)
|
| 196 |
if use_l2warp:
|
|
|
|
| 197 |
g_logits_l2 = torch.zeros_like(c_logits)
|
| 198 |
|
| 199 |
+
# match L2Wrap: normalize by the full number of input tokens, not by non-ignored labels.
|
| 200 |
l2_factor = l2_penalty_factor / N
|
| 201 |
penalty_grad = c_maxx * l2_factor
|
| 202 |
g_logits_l2.scatter_(-1, c_ids, penalty_grad)
|
| 203 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 204 |
if weight is not None:
|
| 205 |
+
torch.addmm(input=dw, mat1=g_logits_l2.t().to(dtype=grad_dtype), mat2=c_x, out=dw)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 206 |
if bias is not None:
|
| 207 |
torch.add(input=db, other=g_logits_l2.sum(0, dtype=bias_grad_dtype), out=db)
|
| 208 |
+
# the dx contribution must be added to the final dx calculation
|
| 209 |
dx_l2_contribution = torch.mm(g_logits_l2, weight)
|
| 210 |
else:
|
| 211 |
dx_l2_contribution = 0.0
|
| 212 |
|
|
|
|
|
|
|
| 213 |
dx[start:end] = torch.mm(c_logits, weight) + dx_l2_contribution
|
| 214 |
|
| 215 |
if weight is not None:
|
| 216 |
+
torch.addmm(input=dw, mat1=c_logits.t().to(dtype=grad_dtype), mat2=c_x, out=dw)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 217 |
|
| 218 |
if bias is not None:
|
| 219 |
torch.add(input=db, other=c_logits.sum(0, dtype=bias_grad_dtype), out=db)
|
| 220 |
|
| 221 |
+
if world_size > 1:
|
| 222 |
+
torch.distributed.all_reduce(dx, group=process_group)
|
| 223 |
loss = loss.sum()
|
| 224 |
+
if reduction == "mean":
|
| 225 |
+
loss = loss / total
|
| 226 |
if dw is not None:
|
| 227 |
dw = dw.to(weight)
|
| 228 |
if db is not None:
|
|
|
|
| 230 |
return loss, dx, dw, db
|
| 231 |
|
| 232 |
|
| 233 |
+
@dispatch
|
| 234 |
+
def fused_linear_cross_entropy_bwd(do: torch.Tensor, dx: torch.Tensor, dw: torch.Tensor, db: torch.Tensor | None):
|
| 235 |
+
# in-place gradient storage across repeated backward calls causes PyTorch anomalies; use Triton.
|
| 236 |
+
N, H = dx.shape
|
| 237 |
+
BN = min(MAX_FUSED_SIZE, triton.next_power_of_2(H))
|
| 238 |
+
|
| 239 |
+
elementwise_mul_kernel[(triton.cdiv(N * H, BN),)](x=dx, g=do, N=N*H, BN=BN, num_warps=STATIC_WARPS)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 240 |
|
| 241 |
+
if dw is not None:
|
| 242 |
+
V, H = dw.shape
|
| 243 |
+
elementwise_mul_kernel[(triton.cdiv(V * H, BN),)](x=dw, g=do, N=V*H, BN=BN, num_warps=STATIC_WARPS)
|
| 244 |
+
|
| 245 |
+
if db is not None:
|
| 246 |
+
V = db.shape[0]
|
| 247 |
+
elementwise_mul_kernel[(triton.cdiv(V, BN),)](x=db, g=do, N=V, BN=BN, num_warps=STATIC_WARPS)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 248 |
return dx, dw, db
|
| 249 |
|
| 250 |
|
| 251 |
+
fused_linear_cross_entropy_forward = fused_linear_cross_entropy_fwd
|
| 252 |
+
|
| 253 |
+
|
| 254 |
+
fused_linear_cross_entropy_backward = fused_linear_cross_entropy_bwd
|
| 255 |
+
|
| 256 |
+
|
| 257 |
class FusedLinearCrossEntropyFunction(torch.autograd.Function):
|
| 258 |
|
| 259 |
@staticmethod
|
|
|
|
| 263 |
x: torch.Tensor,
|
| 264 |
target: torch.LongTensor,
|
| 265 |
weight: torch.Tensor,
|
| 266 |
+
bias: torch.Tensor | None = None,
|
| 267 |
ignore_index: int = -100,
|
| 268 |
label_smoothing: float = 0.0,
|
| 269 |
logit_scale: float = 1.0,
|
| 270 |
+
logit_softcapping: float | None = None,
|
| 271 |
num_chunks: int = 8,
|
| 272 |
reduction: str = "mean",
|
| 273 |
use_l2warp: bool = False,
|
| 274 |
l2_penalty_factor: float = 1e-4,
|
| 275 |
accumulate_grad_in_fp32: bool = True,
|
| 276 |
+
process_group: ProcessGroup | None = None,
|
| 277 |
):
|
| 278 |
+
"""Precompute gradients per token chunk so backward does not retain the logits."""
|
| 279 |
+
loss, dx, dw, db = fused_linear_cross_entropy_fwd(
|
| 280 |
+
x=x,
|
| 281 |
+
target=target,
|
| 282 |
+
weight=weight,
|
| 283 |
+
bias=bias,
|
| 284 |
+
ignore_index=ignore_index,
|
| 285 |
+
label_smoothing=label_smoothing,
|
| 286 |
+
logit_scale=logit_scale,
|
| 287 |
+
logit_softcapping=logit_softcapping,
|
| 288 |
+
num_chunks=num_chunks,
|
| 289 |
+
reduction=reduction,
|
| 290 |
+
use_l2warp=use_l2warp,
|
| 291 |
+
l2_penalty_factor=l2_penalty_factor,
|
| 292 |
+
accumulate_grad_in_fp32=accumulate_grad_in_fp32,
|
| 293 |
+
process_group=process_group,
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 294 |
)
|
|
|
|
| 295 |
ctx.save_for_backward(
|
| 296 |
dx.detach(),
|
| 297 |
dw.detach() if weight is not None else None,
|
|
|
|
| 303 |
@input_guard
|
| 304 |
def backward(ctx, do):
|
| 305 |
dx, dw, db = ctx.saved_tensors
|
| 306 |
+
dx, dw, db = fused_linear_cross_entropy_bwd(do=do, dx=dx, dw=dw, db=db)
|
| 307 |
+
return dx, None, dw, db, None, None, None, None, None, None, None, None, None, None
|
| 308 |
|
| 309 |
|
| 310 |
def fused_linear_cross_entropy_loss(
|
| 311 |
x: torch.Tensor,
|
| 312 |
target: torch.LongTensor,
|
| 313 |
weight: torch.Tensor,
|
| 314 |
+
bias: torch.Tensor | None = None,
|
| 315 |
ignore_index: int = -100,
|
| 316 |
label_smoothing: float = 0.0,
|
| 317 |
logit_scale: float = 1.0,
|
| 318 |
+
logit_softcapping: float | None = None,
|
| 319 |
num_chunks: int = 8,
|
| 320 |
reduction: str = "mean",
|
| 321 |
use_l2warp: bool = False,
|
| 322 |
l2_penalty_factor: float = 1e-4,
|
| 323 |
accumulate_grad_in_fp32: bool = True,
|
| 324 |
+
process_group: ProcessGroup | None = None,
|
| 325 |
+
) -> torch.Tensor:
|
| 326 |
"""
|
| 327 |
Args:
|
| 328 |
+
x (torch.Tensor):
|
| 329 |
+
Input of shape `[batch_size * seq_len, hidden_size]`.
|
| 330 |
+
target (torch.LongTensor):
|
| 331 |
+
Target indices of shape `[batch_size * seq_len]` with values in `[0, vocab_size)`.
|
| 332 |
+
weight (torch.Tensor):
|
| 333 |
+
Projection weight of shape `[vocab_size, hidden_size]` where `vocab_size` is the number of classes.
|
| 334 |
+
bias (torch.Tensor, Optional):
|
| 335 |
+
Projection bias of shape `[vocab_size]`. Default: `None`.
|
| 336 |
+
ignore_index (int, Optional):
|
| 337 |
+
Target index excluded from the loss. Default: -100.
|
| 338 |
+
label_smoothing (float, Optional):
|
| 339 |
+
Uniform label smoothing coefficient. Default: 0.0.
|
| 340 |
+
logit_scale (float, Optional):
|
| 341 |
+
A scaling factor applied to the logits. Default: 1.0.
|
| 342 |
+
logit_softcapping (float, Optional):
|
| 343 |
+
If not `None`, apply logit softcapping: logits = softcap * tanh(logits / softcap).
|
| 344 |
+
Default: `None`.
|
| 345 |
+
num_chunks (int, Optional):
|
| 346 |
The number of chunks to split the input tensor into for processing.
|
| 347 |
This can help optimize memory usage and computation speed.
|
| 348 |
+
Default: 8.
|
| 349 |
+
reduction (str, Optional):
|
| 350 |
Specifies the reduction to apply to the output: 'mean' | 'sum'.
|
| 351 |
'mean': the weighted mean of the output is taken,
|
| 352 |
'sum': the output will be summed.
|
| 353 |
Default: 'mean'.
|
| 354 |
+
use_l2warp (bool, Optional):
|
| 355 |
+
Whether to add the L2Warp logit regularization gradient.
|
| 356 |
+
The penalty is normalized by the full number of input tokens, matching `fla.modules.l2warp.l2_warp`.
|
| 357 |
Default: `False`.
|
| 358 |
+
l2_penalty_factor (float, Optional):
|
| 359 |
The L2Warp penalty factor. Default: `1e-4`.
|
| 360 |
+
accumulate_grad_in_fp32 (bool, Optional):
|
| 361 |
+
Whether to accumulate weight and bias gradients in fp32 before casting them back to the parameter dtype.
|
| 362 |
+
Default: `True`.
|
| 363 |
+
process_group (ProcessGroup, Optional):
|
| 364 |
+
Group with equal contiguous vocabulary shards of weight and bias, and replicated inputs and targets.
|
| 365 |
+
Loss and input gradients are replicated; weight and bias gradients remain sharded. Default: `None`.
|
| 366 |
+
Multi-rank groups are not supported by the Ascend backend.
|
| 367 |
+
|
| 368 |
Returns:
|
| 369 |
+
torch.Tensor:
|
| 370 |
+
Scalar loss in fp32.
|
| 371 |
"""
|
| 372 |
return FusedLinearCrossEntropyFunction.apply(
|
| 373 |
x,
|
|
|
|
| 383 |
use_l2warp,
|
| 384 |
l2_penalty_factor,
|
| 385 |
accumulate_grad_in_fp32,
|
| 386 |
+
process_group,
|
| 387 |
)
|
| 388 |
|
| 389 |
|
|
|
|
| 394 |
ignore_index: int = -100,
|
| 395 |
label_smoothing: float = 0.0,
|
| 396 |
logit_scale: float = 1.0,
|
| 397 |
+
logit_softcapping: float | None = None,
|
| 398 |
num_chunks: int = 8,
|
| 399 |
reduction: str = "mean",
|
| 400 |
use_l2warp: bool = False,
|
| 401 |
l2_penalty_factor: float = 1e-4,
|
| 402 |
accumulate_grad_in_fp32: bool = True,
|
| 403 |
+
process_group: ProcessGroup | None = None,
|
| 404 |
):
|
| 405 |
"""
|
| 406 |
Args:
|
| 407 |
+
ignore_index (int, Optional):
|
| 408 |
+
Target index excluded from the loss. Default: -100.
|
| 409 |
+
label_smoothing (float, Optional):
|
| 410 |
+
Uniform label smoothing coefficient. Default: 0.0.
|
| 411 |
+
logit_scale (float, Optional):
|
| 412 |
+
A scaling factor applied to the logits. Default: 1.0.
|
| 413 |
+
logit_softcapping (float, Optional):
|
| 414 |
+
If not `None`, apply logit softcapping: logits = softcap * tanh(logits / softcap).
|
| 415 |
+
Default: `None`.
|
| 416 |
+
num_chunks (int, Optional):
|
| 417 |
The number of chunks to split the input tensor into for processing.
|
| 418 |
This can help optimize memory usage and computation speed.
|
| 419 |
+
Default: 8.
|
| 420 |
+
reduction (str, Optional):
|
| 421 |
Specifies the reduction to apply to the output: 'mean' | 'sum'.
|
| 422 |
'mean': the weighted mean of the output is taken,
|
| 423 |
'sum': the output will be summed.
|
| 424 |
Default: 'mean'.
|
| 425 |
+
use_l2warp (bool, Optional):
|
| 426 |
+
Whether to add the L2Warp logit regularization gradient.
|
| 427 |
+
The penalty is normalized by the full number of input tokens, matching `fla.modules.l2warp.l2_warp`.
|
| 428 |
Default: `False`.
|
| 429 |
+
l2_penalty_factor (float, Optional):
|
| 430 |
The L2Warp penalty factor. Default: `1e-4`.
|
| 431 |
+
accumulate_grad_in_fp32 (bool, Optional):
|
| 432 |
+
Whether to accumulate weight and bias gradients in fp32 before casting them back to the parameter dtype.
|
| 433 |
+
Default: `True`.
|
| 434 |
+
process_group (ProcessGroup, Optional):
|
| 435 |
+
Group with equal contiguous vocabulary shards of weight and bias, and replicated inputs and targets.
|
| 436 |
+
Loss and input gradients are replicated; weight and bias gradients remain sharded. Default: `None`.
|
| 437 |
+
Multi-rank groups are not supported by the Ascend backend.
|
| 438 |
"""
|
| 439 |
super().__init__()
|
| 440 |
|
|
|
|
| 449 |
self.use_l2warp = use_l2warp
|
| 450 |
self.l2_penalty_factor = l2_penalty_factor
|
| 451 |
self.accumulate_grad_in_fp32 = accumulate_grad_in_fp32
|
| 452 |
+
self.process_group = process_group
|
| 453 |
|
| 454 |
@torch.compiler.disable
|
| 455 |
+
def forward(self, x: torch.Tensor, target: torch.LongTensor, weight: torch.Tensor, bias: torch.Tensor | None = None):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 456 |
"""
|
| 457 |
Args:
|
| 458 |
+
x (torch.Tensor):
|
| 459 |
+
Input of shape `[batch_size, seq_len, hidden_size]`.
|
| 460 |
+
target (torch.LongTensor):
|
| 461 |
+
Target indices of shape `[batch_size, seq_len]` with values in `[0, vocab_size)`.
|
| 462 |
+
weight (torch.Tensor):
|
| 463 |
+
Projection weight of shape `[vocab_size, hidden_size]` where `vocab_size` is the number of classes.
|
| 464 |
+
bias (torch.Tensor, Optional):
|
| 465 |
+
Projection bias of shape `[vocab_size]`. Default: `None`.
|
| 466 |
+
|
| 467 |
Returns:
|
| 468 |
+
torch.Tensor:
|
| 469 |
+
Scalar loss in fp32.
|
| 470 |
"""
|
| 471 |
loss = fused_linear_cross_entropy_loss(
|
| 472 |
+
x=x.reshape(-1, x.shape[-1]),
|
| 473 |
+
target=target.reshape(-1),
|
| 474 |
weight=weight,
|
| 475 |
bias=bias,
|
| 476 |
ignore_index=self.ignore_index,
|
|
|
|
| 482 |
use_l2warp=self.use_l2warp,
|
| 483 |
l2_penalty_factor=self.l2_penalty_factor,
|
| 484 |
accumulate_grad_in_fp32=self.accumulate_grad_in_fp32,
|
| 485 |
+
process_group=self.process_group,
|
| 486 |
)
|
| 487 |
return loss
|
| 488 |
|
| 489 |
|
| 490 |
class LinearLossParallel(ParallelStyle):
|
| 491 |
+
def __init__(self, *, sequence_dim: int = 1, use_local_output: bool = False):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 492 |
super().__init__()
|
| 493 |
|
| 494 |
self.sequence_sharding = (Shard(sequence_dim),)
|
|
|
|
| 523 |
|
| 524 |
@staticmethod
|
| 525 |
def _prepare_output_fn(use_local_output, mod, outputs, device_mesh):
|
| 526 |
+
return outputs.to_local() if use_local_output and isinstance(outputs, DTensor) else outputs
|
| 527 |
|
| 528 |
def _apply(self, module: nn.Module, device_mesh: DeviceMesh) -> nn.Module:
|
| 529 |
return distribute_module(
|
build/torch-cuda/modules/fused_norm_gate.py
DELETED
|
@@ -1,1245 +0,0 @@
|
|
| 1 |
-
# Copyright (c) 2023-2026, Songlin Yang, Yu Zhang, Zhiyuan Li
|
| 2 |
-
#
|
| 3 |
-
# This source code is licensed under the MIT license found in the
|
| 4 |
-
# LICENSE file in the root directory of this source tree.
|
| 5 |
-
# For a list of all contributors, visit:
|
| 6 |
-
# https://github.com/fla-org/flash-linear-attention/graphs/contributors
|
| 7 |
-
|
| 8 |
-
from __future__ import annotations
|
| 9 |
-
|
| 10 |
-
import math
|
| 11 |
-
|
| 12 |
-
import torch
|
| 13 |
-
import torch.nn as nn
|
| 14 |
-
import torch.nn.functional as F
|
| 15 |
-
import triton
|
| 16 |
-
import triton.language as tl
|
| 17 |
-
|
| 18 |
-
from ..utils import autotune_cache_kwargs, get_multiprocessor_count, input_guard
|
| 19 |
-
|
| 20 |
-
|
| 21 |
-
@triton.heuristics(
|
| 22 |
-
{
|
| 23 |
-
"STORE_RESIDUAL_OUT": lambda args: args["residual_out"] is not None,
|
| 24 |
-
"HAS_RESIDUAL": lambda args: args["residual"] is not None,
|
| 25 |
-
"HAS_WEIGHT": lambda args: args["w"] is not None,
|
| 26 |
-
"HAS_BIAS": lambda args: args["b"] is not None,
|
| 27 |
-
}
|
| 28 |
-
)
|
| 29 |
-
@triton.autotune(
|
| 30 |
-
configs=[triton.Config({"BT": BT}, num_warps=num_warps) for BT in [16, 32, 64] for num_warps in [4, 8, 16]],
|
| 31 |
-
key=["D", "NB", "IS_RMS_NORM", "STORE_RESIDUAL_OUT", "HAS_RESIDUAL", "HAS_WEIGHT"],
|
| 32 |
-
**autotune_cache_kwargs,
|
| 33 |
-
)
|
| 34 |
-
@triton.jit
|
| 35 |
-
def layer_norm_gated_fwd_kernel(
|
| 36 |
-
x, # pointer to the input
|
| 37 |
-
g, # pointer to the gate
|
| 38 |
-
y, # pointer to the output
|
| 39 |
-
w, # pointer to the weights
|
| 40 |
-
b, # pointer to the biases
|
| 41 |
-
residual, # pointer to the residual
|
| 42 |
-
residual_out, # pointer to the residual
|
| 43 |
-
mean, # pointer to the mean
|
| 44 |
-
rstd, # pointer to the 1/std
|
| 45 |
-
eps, # epsilon to avoid division by zero
|
| 46 |
-
T, # number of rows in x
|
| 47 |
-
D: tl.constexpr, # number of columns in x
|
| 48 |
-
BT: tl.constexpr,
|
| 49 |
-
BD: tl.constexpr,
|
| 50 |
-
NB: tl.constexpr,
|
| 51 |
-
ACTIVATION: tl.constexpr,
|
| 52 |
-
IS_RMS_NORM: tl.constexpr,
|
| 53 |
-
STORE_RESIDUAL_OUT: tl.constexpr,
|
| 54 |
-
HAS_RESIDUAL: tl.constexpr,
|
| 55 |
-
HAS_WEIGHT: tl.constexpr,
|
| 56 |
-
HAS_BIAS: tl.constexpr,
|
| 57 |
-
):
|
| 58 |
-
i_t = tl.program_id(0)
|
| 59 |
-
|
| 60 |
-
o_d = tl.arange(0, BD)
|
| 61 |
-
m_d = o_d < D
|
| 62 |
-
|
| 63 |
-
p_x = tl.make_block_ptr(x, (T, D), (D, 1), (i_t * BT, 0), (BT, BD), (1, 0))
|
| 64 |
-
b_x = tl.load(p_x, boundary_check=(0, 1)).to(tl.float32)
|
| 65 |
-
if HAS_RESIDUAL:
|
| 66 |
-
p_res = tl.make_block_ptr(residual, (T, D), (D, 1), (i_t * BT, 0), (BT, BD), (1, 0))
|
| 67 |
-
b_x += tl.load(p_res, boundary_check=(0, 1)).to(tl.float32)
|
| 68 |
-
if STORE_RESIDUAL_OUT:
|
| 69 |
-
p_res_out = tl.make_block_ptr(residual_out, (T, D), (D, 1), (i_t * BT, 0), (BT, BD), (1, 0))
|
| 70 |
-
tl.store(p_res_out, b_x.to(p_res_out.dtype.element_ty), boundary_check=(0, 1))
|
| 71 |
-
if not IS_RMS_NORM:
|
| 72 |
-
b_mean = tl.sum(b_x, axis=1) / D
|
| 73 |
-
p_mean = tl.make_block_ptr(mean, (T,), (1,), (i_t * BT,), (BT,), (0,))
|
| 74 |
-
tl.store(p_mean, b_mean.to(p_mean.dtype.element_ty), boundary_check=(0,))
|
| 75 |
-
b_xbar = tl.where(m_d[None, :], b_x - b_mean[:, None], 0.0)
|
| 76 |
-
b_var = tl.sum(b_xbar * b_xbar, axis=1) / D
|
| 77 |
-
else:
|
| 78 |
-
b_xbar = tl.where(m_d[None, :], b_x, 0.0)
|
| 79 |
-
b_var = tl.sum(b_xbar * b_xbar, axis=1) / D
|
| 80 |
-
b_rstd = 1 / tl.sqrt(b_var + eps)
|
| 81 |
-
|
| 82 |
-
p_rstd = tl.make_block_ptr(rstd, (T,), (1,), (i_t * BT,), (BT,), (0,))
|
| 83 |
-
tl.store(p_rstd, b_rstd.to(p_rstd.dtype.element_ty), boundary_check=(0,))
|
| 84 |
-
|
| 85 |
-
if HAS_WEIGHT:
|
| 86 |
-
b_w = tl.load(w + o_d, mask=m_d).to(tl.float32)
|
| 87 |
-
if HAS_BIAS:
|
| 88 |
-
b_b = tl.load(b + o_d, mask=m_d).to(tl.float32)
|
| 89 |
-
b_x_hat = (b_x - b_mean[:, None]) * b_rstd[:, None] if not IS_RMS_NORM else b_x * b_rstd[:, None]
|
| 90 |
-
b_y = b_x_hat * b_w[None, :] if HAS_WEIGHT else b_x_hat
|
| 91 |
-
if HAS_BIAS:
|
| 92 |
-
b_y = b_y + b_b[None, :]
|
| 93 |
-
|
| 94 |
-
# swish/sigmoid output gate
|
| 95 |
-
p_g = tl.make_block_ptr(g, (T, D), (D, 1), (i_t * BT, 0), (BT, BD), (1, 0))
|
| 96 |
-
b_g = tl.load(p_g, boundary_check=(0, 1)).to(tl.float32)
|
| 97 |
-
if ACTIVATION == "swish" or ACTIVATION == "silu":
|
| 98 |
-
b_y = b_y * b_g * tl.sigmoid(b_g)
|
| 99 |
-
elif ACTIVATION == "sigmoid":
|
| 100 |
-
b_y = b_y * tl.sigmoid(b_g)
|
| 101 |
-
|
| 102 |
-
# Write output
|
| 103 |
-
p_y = tl.make_block_ptr(y, (T, D), (D, 1), (i_t * BT, 0), (BT, BD), (1, 0))
|
| 104 |
-
tl.store(p_y, b_y.to(p_y.dtype.element_ty), boundary_check=(0, 1))
|
| 105 |
-
|
| 106 |
-
|
| 107 |
-
@triton.heuristics(
|
| 108 |
-
{
|
| 109 |
-
"STORE_RESIDUAL_OUT": lambda args: args["residual_out"] is not None,
|
| 110 |
-
"HAS_RESIDUAL": lambda args: args["residual"] is not None,
|
| 111 |
-
"HAS_WEIGHT": lambda args: args["w"] is not None,
|
| 112 |
-
"HAS_BIAS": lambda args: args["b"] is not None,
|
| 113 |
-
}
|
| 114 |
-
)
|
| 115 |
-
@triton.autotune(
|
| 116 |
-
configs=[triton.Config({}, num_warps=num_warps) for num_warps in [2, 4, 8, 16]],
|
| 117 |
-
key=["D", "IS_RMS_NORM", "STORE_RESIDUAL_OUT", "HAS_RESIDUAL", "HAS_WEIGHT"],
|
| 118 |
-
**autotune_cache_kwargs,
|
| 119 |
-
)
|
| 120 |
-
@triton.jit
|
| 121 |
-
def layer_norm_gated_fwd_kernel1(
|
| 122 |
-
x, # pointer to the input
|
| 123 |
-
g, # pointer to the gate
|
| 124 |
-
y, # pointer to the output
|
| 125 |
-
w, # pointer to the weights
|
| 126 |
-
b, # pointer to the biases
|
| 127 |
-
residual, # pointer to the residual
|
| 128 |
-
residual_out, # pointer to the residual
|
| 129 |
-
mean, # pointer to the mean
|
| 130 |
-
rstd, # pointer to the 1/std
|
| 131 |
-
eps, # epsilon to avoid division by zero
|
| 132 |
-
D: tl.constexpr, # number of columns in x
|
| 133 |
-
BD: tl.constexpr,
|
| 134 |
-
ACTIVATION: tl.constexpr,
|
| 135 |
-
IS_RMS_NORM: tl.constexpr,
|
| 136 |
-
STORE_RESIDUAL_OUT: tl.constexpr,
|
| 137 |
-
HAS_RESIDUAL: tl.constexpr,
|
| 138 |
-
HAS_WEIGHT: tl.constexpr,
|
| 139 |
-
HAS_BIAS: tl.constexpr,
|
| 140 |
-
):
|
| 141 |
-
i_t = tl.program_id(0)
|
| 142 |
-
x += i_t * D
|
| 143 |
-
y += i_t * D
|
| 144 |
-
g += i_t * D
|
| 145 |
-
if HAS_RESIDUAL:
|
| 146 |
-
residual += i_t * D
|
| 147 |
-
if STORE_RESIDUAL_OUT:
|
| 148 |
-
residual_out += i_t * D
|
| 149 |
-
|
| 150 |
-
o_d = tl.arange(0, BD)
|
| 151 |
-
m_d = o_d < D
|
| 152 |
-
b_x = tl.load(x + o_d, mask=m_d, other=0.0).to(tl.float32)
|
| 153 |
-
if HAS_RESIDUAL:
|
| 154 |
-
b_x += tl.load(residual + o_d, mask=m_d, other=0.0).to(tl.float32)
|
| 155 |
-
if STORE_RESIDUAL_OUT:
|
| 156 |
-
tl.store(residual_out + o_d, b_x, mask=m_d)
|
| 157 |
-
if not IS_RMS_NORM:
|
| 158 |
-
b_mean = tl.sum(b_x, axis=0) / D
|
| 159 |
-
tl.store(mean + i_t, b_mean)
|
| 160 |
-
b_xbar = tl.where(m_d, b_x - b_mean, 0.0)
|
| 161 |
-
b_var = tl.sum(b_xbar * b_xbar, axis=0) / D
|
| 162 |
-
else:
|
| 163 |
-
b_xbar = tl.where(m_d, b_x, 0.0)
|
| 164 |
-
b_var = tl.sum(b_xbar * b_xbar, axis=0) / D
|
| 165 |
-
b_rstd = 1 / tl.sqrt(b_var + eps)
|
| 166 |
-
tl.store(rstd + i_t, b_rstd)
|
| 167 |
-
|
| 168 |
-
if HAS_WEIGHT:
|
| 169 |
-
b_w = tl.load(w + o_d, mask=m_d).to(tl.float32)
|
| 170 |
-
if HAS_BIAS:
|
| 171 |
-
b_b = tl.load(b + o_d, mask=m_d).to(tl.float32)
|
| 172 |
-
b_x_hat = (b_x - b_mean) * b_rstd if not IS_RMS_NORM else b_x * b_rstd
|
| 173 |
-
b_y = b_x_hat * b_w if HAS_WEIGHT else b_x_hat
|
| 174 |
-
if HAS_BIAS:
|
| 175 |
-
b_y = b_y + b_b
|
| 176 |
-
|
| 177 |
-
# swish/sigmoid output gate
|
| 178 |
-
b_g = tl.load(g + o_d, mask=m_d, other=0.0).to(tl.float32)
|
| 179 |
-
if ACTIVATION == "swish" or ACTIVATION == "silu":
|
| 180 |
-
b_y = b_y * b_g * tl.sigmoid(b_g)
|
| 181 |
-
elif ACTIVATION == "sigmoid":
|
| 182 |
-
b_y = b_y * tl.sigmoid(b_g)
|
| 183 |
-
|
| 184 |
-
# Write output
|
| 185 |
-
tl.store(y + o_d, b_y, mask=m_d)
|
| 186 |
-
|
| 187 |
-
|
| 188 |
-
@triton.heuristics(
|
| 189 |
-
{
|
| 190 |
-
"HAS_DRESIDUAL": lambda args: args["dresidual"] is not None,
|
| 191 |
-
"HAS_WEIGHT": lambda args: args["w"] is not None,
|
| 192 |
-
"HAS_BIAS": lambda args: args["b"] is not None,
|
| 193 |
-
"RECOMPUTE_OUTPUT": lambda args: args["y"] is not None,
|
| 194 |
-
}
|
| 195 |
-
)
|
| 196 |
-
@triton.autotune(
|
| 197 |
-
configs=[triton.Config({"BT": BT}, num_warps=num_warps) for BT in [16, 32, 64] for num_warps in [4, 8, 16]],
|
| 198 |
-
key=["D", "NB", "IS_RMS_NORM", "HAS_DRESIDUAL", "HAS_WEIGHT"],
|
| 199 |
-
**autotune_cache_kwargs,
|
| 200 |
-
)
|
| 201 |
-
@triton.jit
|
| 202 |
-
def layer_norm_gated_bwd_kernel(
|
| 203 |
-
x, # pointer to the input
|
| 204 |
-
g, # pointer to the gate
|
| 205 |
-
w, # pointer to the weights
|
| 206 |
-
b, # pointer to the biases
|
| 207 |
-
y, # pointer to the output to be recomputed
|
| 208 |
-
dy, # pointer to the output gradient
|
| 209 |
-
dx, # pointer to the input gradient
|
| 210 |
-
dg, # pointer to the gate gradient
|
| 211 |
-
dw, # pointer to the partial sum of weights gradient
|
| 212 |
-
db, # pointer to the partial sum of biases gradient
|
| 213 |
-
dresidual,
|
| 214 |
-
dresidual_in,
|
| 215 |
-
mean,
|
| 216 |
-
rstd,
|
| 217 |
-
T,
|
| 218 |
-
BS,
|
| 219 |
-
D: tl.constexpr,
|
| 220 |
-
BT: tl.constexpr,
|
| 221 |
-
BD: tl.constexpr,
|
| 222 |
-
NB: tl.constexpr,
|
| 223 |
-
ACTIVATION: tl.constexpr,
|
| 224 |
-
IS_RMS_NORM: tl.constexpr,
|
| 225 |
-
STORE_DRESIDUAL: tl.constexpr,
|
| 226 |
-
HAS_DRESIDUAL: tl.constexpr,
|
| 227 |
-
HAS_WEIGHT: tl.constexpr,
|
| 228 |
-
HAS_BIAS: tl.constexpr,
|
| 229 |
-
RECOMPUTE_OUTPUT: tl.constexpr,
|
| 230 |
-
):
|
| 231 |
-
i_s = tl.program_id(0)
|
| 232 |
-
o_d = tl.arange(0, BD)
|
| 233 |
-
m_d = o_d < D
|
| 234 |
-
if HAS_WEIGHT:
|
| 235 |
-
b_w = tl.load(w + o_d, mask=m_d).to(tl.float32)
|
| 236 |
-
b_dw = tl.zeros((BT, BD), dtype=tl.float32)
|
| 237 |
-
if HAS_BIAS:
|
| 238 |
-
b_b = tl.load(b + o_d, mask=m_d, other=0.0).to(tl.float32)
|
| 239 |
-
b_db = tl.zeros((BT, BD), dtype=tl.float32)
|
| 240 |
-
|
| 241 |
-
# the caller guarantees NS = min(SM, T), so every program has at least one token.
|
| 242 |
-
# the last program's range may slightly exceed T (since BS = ceil(T/NS));
|
| 243 |
-
# make_block_ptr uses the true tensor shape (T, D), so boundary_check
|
| 244 |
-
# handles the partial tail tile by zero-padding loads and skipping stores.
|
| 245 |
-
# the m_t mask below further ensures dw/db only accumulate valid rows (< T).
|
| 246 |
-
for i_t in range(i_s * BS, i_s * BS + BS, BT):
|
| 247 |
-
p_x = tl.make_block_ptr(x, (T, D), (D, 1), (i_t, 0), (BT, BD), (1, 0))
|
| 248 |
-
p_g = tl.make_block_ptr(g, (T, D), (D, 1), (i_t, 0), (BT, BD), (1, 0))
|
| 249 |
-
p_dy = tl.make_block_ptr(dy, (T, D), (D, 1), (i_t, 0), (BT, BD), (1, 0))
|
| 250 |
-
p_dx = tl.make_block_ptr(dx, (T, D), (D, 1), (i_t, 0), (BT, BD), (1, 0))
|
| 251 |
-
p_dg = tl.make_block_ptr(dg, (T, D), (D, 1), (i_t, 0), (BT, BD), (1, 0))
|
| 252 |
-
# [BT, BD]
|
| 253 |
-
b_x = tl.load(p_x, boundary_check=(0, 1)).to(tl.float32)
|
| 254 |
-
b_g = tl.load(p_g, boundary_check=(0, 1)).to(tl.float32)
|
| 255 |
-
b_dy = tl.load(p_dy, boundary_check=(0, 1)).to(tl.float32)
|
| 256 |
-
|
| 257 |
-
if not IS_RMS_NORM:
|
| 258 |
-
p_mean = tl.make_block_ptr(mean, (T,), (1,), (i_t,), (BT,), (0,))
|
| 259 |
-
b_mean = tl.load(p_mean, boundary_check=(0,))
|
| 260 |
-
p_rstd = tl.make_block_ptr(rstd, (T,), (1,), (i_t,), (BT,), (0,))
|
| 261 |
-
b_rstd = tl.load(p_rstd, boundary_check=(0,))
|
| 262 |
-
# Compute dx
|
| 263 |
-
b_xhat = (b_x - b_mean[:, None]) * b_rstd[:, None] if not IS_RMS_NORM else b_x * b_rstd[:, None]
|
| 264 |
-
b_xhat = tl.where(m_d[None, :], b_xhat, 0.0)
|
| 265 |
-
|
| 266 |
-
b_y = b_xhat * b_w[None, :] if HAS_WEIGHT else b_xhat
|
| 267 |
-
if HAS_BIAS:
|
| 268 |
-
b_y = b_y + b_b[None, :]
|
| 269 |
-
if RECOMPUTE_OUTPUT:
|
| 270 |
-
p_y = tl.make_block_ptr(y, (T, D), (D, 1), (i_t, 0), (BT, BD), (1, 0))
|
| 271 |
-
tl.store(p_y, b_y.to(p_y.dtype.element_ty), boundary_check=(0, 1))
|
| 272 |
-
|
| 273 |
-
b_sigmoid_g = tl.sigmoid(b_g)
|
| 274 |
-
if ACTIVATION == "swish" or ACTIVATION == "silu":
|
| 275 |
-
b_dg = b_dy * b_y * (b_sigmoid_g + b_g * b_sigmoid_g * (1 - b_sigmoid_g))
|
| 276 |
-
b_dy = b_dy * b_g * b_sigmoid_g
|
| 277 |
-
elif ACTIVATION == "sigmoid":
|
| 278 |
-
b_dg = b_dy * b_y * b_sigmoid_g * (1 - b_sigmoid_g)
|
| 279 |
-
b_dy = b_dy * b_sigmoid_g
|
| 280 |
-
b_wdy = b_dy
|
| 281 |
-
|
| 282 |
-
if HAS_WEIGHT or HAS_BIAS:
|
| 283 |
-
# when BT > BS, a tile may span into the next program's range;
|
| 284 |
-
# mask to this program's upper bound to avoid double-counting dw/db.
|
| 285 |
-
m_t = (i_t + tl.arange(0, BT)) < min(i_s * BS + BS, T)
|
| 286 |
-
if HAS_WEIGHT:
|
| 287 |
-
b_wdy = b_dy * b_w
|
| 288 |
-
b_dw += tl.where(m_t[:, None], b_dy * b_xhat, 0.0)
|
| 289 |
-
if HAS_BIAS:
|
| 290 |
-
b_db += tl.where(m_t[:, None], b_dy, 0.0)
|
| 291 |
-
if not IS_RMS_NORM:
|
| 292 |
-
b_c1 = tl.sum(b_xhat * b_wdy, axis=1) / D
|
| 293 |
-
b_c2 = tl.sum(b_wdy, axis=1) / D
|
| 294 |
-
b_dx = (b_wdy - (b_xhat * b_c1[:, None] + b_c2[:, None])) * b_rstd[:, None]
|
| 295 |
-
else:
|
| 296 |
-
b_c1 = tl.sum(b_xhat * b_wdy, axis=1) / D
|
| 297 |
-
b_dx = (b_wdy - b_xhat * b_c1[:, None]) * b_rstd[:, None]
|
| 298 |
-
if HAS_DRESIDUAL:
|
| 299 |
-
p_dres = tl.make_block_ptr(dresidual, (T, D), (D, 1), (i_t, 0), (BT, BD), (1, 0))
|
| 300 |
-
b_dres = tl.load(p_dres, boundary_check=(0, 1)).to(tl.float32)
|
| 301 |
-
b_dx += b_dres
|
| 302 |
-
# Write dx
|
| 303 |
-
if STORE_DRESIDUAL:
|
| 304 |
-
p_dres_in = tl.make_block_ptr(dresidual_in, (T, D), (D, 1), (i_t, 0), (BT, BD), (1, 0))
|
| 305 |
-
tl.store(p_dres_in, b_dx.to(p_dres_in.dtype.element_ty), boundary_check=(0, 1))
|
| 306 |
-
|
| 307 |
-
tl.store(p_dx, b_dx.to(p_dx.dtype.element_ty), boundary_check=(0, 1))
|
| 308 |
-
tl.store(p_dg, b_dg.to(p_dg.dtype.element_ty), boundary_check=(0, 1))
|
| 309 |
-
|
| 310 |
-
if HAS_WEIGHT:
|
| 311 |
-
tl.store(dw + i_s * D + o_d, tl.sum(b_dw, axis=0), mask=m_d)
|
| 312 |
-
if HAS_BIAS:
|
| 313 |
-
tl.store(db + i_s * D + o_d, tl.sum(b_db, axis=0), mask=m_d)
|
| 314 |
-
|
| 315 |
-
|
| 316 |
-
@triton.heuristics(
|
| 317 |
-
{
|
| 318 |
-
"HAS_DRESIDUAL": lambda args: args["dresidual"] is not None,
|
| 319 |
-
"HAS_WEIGHT": lambda args: args["w"] is not None,
|
| 320 |
-
"HAS_BIAS": lambda args: args["b"] is not None,
|
| 321 |
-
"RECOMPUTE_OUTPUT": lambda args: args["y"] is not None,
|
| 322 |
-
}
|
| 323 |
-
)
|
| 324 |
-
@triton.autotune(
|
| 325 |
-
configs=[triton.Config({}, num_warps=num_warps) for num_warps in [2, 4, 8, 16]],
|
| 326 |
-
key=["D", "IS_RMS_NORM", "STORE_DRESIDUAL", "HAS_DRESIDUAL", "HAS_WEIGHT"],
|
| 327 |
-
**autotune_cache_kwargs,
|
| 328 |
-
)
|
| 329 |
-
@triton.jit
|
| 330 |
-
def layer_norm_gated_bwd_kernel1(
|
| 331 |
-
x, # pointer to the input
|
| 332 |
-
g, # pointer to the gate
|
| 333 |
-
w, # pointer to the weights
|
| 334 |
-
b, # pointer to the biases
|
| 335 |
-
y, # pointer to the output to be recomputed
|
| 336 |
-
dy, # pointer to the output gradient
|
| 337 |
-
dx, # pointer to the input gradient
|
| 338 |
-
dg, # pointer to the gate gradient
|
| 339 |
-
dw, # pointer to the partial sum of weights gradient
|
| 340 |
-
db, # pointer to the partial sum of biases gradient
|
| 341 |
-
dresidual,
|
| 342 |
-
dresidual_in,
|
| 343 |
-
mean,
|
| 344 |
-
rstd,
|
| 345 |
-
T,
|
| 346 |
-
BS,
|
| 347 |
-
D: tl.constexpr,
|
| 348 |
-
BD: tl.constexpr,
|
| 349 |
-
ACTIVATION: tl.constexpr,
|
| 350 |
-
IS_RMS_NORM: tl.constexpr,
|
| 351 |
-
STORE_DRESIDUAL: tl.constexpr,
|
| 352 |
-
HAS_DRESIDUAL: tl.constexpr,
|
| 353 |
-
HAS_WEIGHT: tl.constexpr,
|
| 354 |
-
HAS_BIAS: tl.constexpr,
|
| 355 |
-
RECOMPUTE_OUTPUT: tl.constexpr,
|
| 356 |
-
):
|
| 357 |
-
i_s = tl.program_id(0)
|
| 358 |
-
o_d = tl.arange(0, BD)
|
| 359 |
-
mask = o_d < D
|
| 360 |
-
x += i_s * BS * D
|
| 361 |
-
g += i_s * BS * D
|
| 362 |
-
if HAS_DRESIDUAL:
|
| 363 |
-
dresidual += i_s * BS * D
|
| 364 |
-
if STORE_DRESIDUAL:
|
| 365 |
-
dresidual_in += i_s * BS * D
|
| 366 |
-
dy += i_s * BS * D
|
| 367 |
-
dx += i_s * BS * D
|
| 368 |
-
dg += i_s * BS * D
|
| 369 |
-
if RECOMPUTE_OUTPUT:
|
| 370 |
-
y += i_s * BS * D
|
| 371 |
-
if HAS_WEIGHT:
|
| 372 |
-
b_w = tl.load(w + o_d, mask=mask).to(tl.float32)
|
| 373 |
-
b_dw = tl.zeros((BD,), dtype=tl.float32)
|
| 374 |
-
if HAS_BIAS:
|
| 375 |
-
b_b = tl.load(b + o_d, mask=mask, other=0.0).to(tl.float32)
|
| 376 |
-
b_db = tl.zeros((BD,), dtype=tl.float32)
|
| 377 |
-
|
| 378 |
-
for i_t in range(i_s * BS, min(i_s * BS + BS, T)):
|
| 379 |
-
# Load data to SRAM
|
| 380 |
-
b_x = tl.load(x + o_d, mask=mask, other=0).to(tl.float32)
|
| 381 |
-
b_g = tl.load(g + o_d, mask=mask, other=0).to(tl.float32)
|
| 382 |
-
b_dy = tl.load(dy + o_d, mask=mask, other=0).to(tl.float32)
|
| 383 |
-
|
| 384 |
-
if not IS_RMS_NORM:
|
| 385 |
-
b_mean = tl.load(mean + i_t)
|
| 386 |
-
b_rstd = tl.load(rstd + i_t)
|
| 387 |
-
# Compute dx
|
| 388 |
-
b_xhat = (b_x - b_mean) * b_rstd if not IS_RMS_NORM else b_x * b_rstd
|
| 389 |
-
b_xhat = tl.where(mask, b_xhat, 0.0)
|
| 390 |
-
|
| 391 |
-
b_y = b_xhat * b_w if HAS_WEIGHT else b_xhat
|
| 392 |
-
if HAS_BIAS:
|
| 393 |
-
b_y = b_y + b_b
|
| 394 |
-
if RECOMPUTE_OUTPUT:
|
| 395 |
-
tl.store(y + o_d, b_y, mask=mask)
|
| 396 |
-
|
| 397 |
-
b_sigmoid_g = tl.sigmoid(b_g)
|
| 398 |
-
if ACTIVATION == "swish" or ACTIVATION == "silu":
|
| 399 |
-
b_dg = b_dy * b_y * (b_sigmoid_g + b_g * b_sigmoid_g * (1 - b_sigmoid_g))
|
| 400 |
-
b_dy = b_dy * b_g * b_sigmoid_g
|
| 401 |
-
elif ACTIVATION == "sigmoid":
|
| 402 |
-
b_dg = b_dy * b_y * b_sigmoid_g * (1 - b_sigmoid_g)
|
| 403 |
-
b_dy = b_dy * b_sigmoid_g
|
| 404 |
-
b_wdy = b_dy
|
| 405 |
-
if HAS_WEIGHT:
|
| 406 |
-
b_wdy = b_dy * b_w
|
| 407 |
-
b_dw += b_dy * b_xhat
|
| 408 |
-
if HAS_BIAS:
|
| 409 |
-
b_db += b_dy
|
| 410 |
-
if not IS_RMS_NORM:
|
| 411 |
-
b_c1 = tl.sum(b_xhat * b_wdy, axis=0) / D
|
| 412 |
-
b_c2 = tl.sum(b_wdy, axis=0) / D
|
| 413 |
-
b_dx = (b_wdy - (b_xhat * b_c1 + b_c2)) * b_rstd
|
| 414 |
-
else:
|
| 415 |
-
b_c1 = tl.sum(b_xhat * b_wdy, axis=0) / D
|
| 416 |
-
b_dx = (b_wdy - b_xhat * b_c1) * b_rstd
|
| 417 |
-
if HAS_DRESIDUAL:
|
| 418 |
-
b_dres = tl.load(dresidual + o_d, mask=mask, other=0).to(tl.float32)
|
| 419 |
-
b_dx += b_dres
|
| 420 |
-
# Write dx
|
| 421 |
-
if STORE_DRESIDUAL:
|
| 422 |
-
tl.store(dresidual_in + o_d, b_dx, mask=mask)
|
| 423 |
-
tl.store(dx + o_d, b_dx, mask=mask)
|
| 424 |
-
tl.store(dg + o_d, b_dg, mask=mask)
|
| 425 |
-
|
| 426 |
-
x += D
|
| 427 |
-
g += D
|
| 428 |
-
if HAS_DRESIDUAL:
|
| 429 |
-
dresidual += D
|
| 430 |
-
if STORE_DRESIDUAL:
|
| 431 |
-
dresidual_in += D
|
| 432 |
-
if RECOMPUTE_OUTPUT:
|
| 433 |
-
y += D
|
| 434 |
-
dy += D
|
| 435 |
-
dx += D
|
| 436 |
-
dg += D
|
| 437 |
-
if HAS_WEIGHT:
|
| 438 |
-
tl.store(dw + i_s * D + o_d, b_dw, mask=mask)
|
| 439 |
-
if HAS_BIAS:
|
| 440 |
-
tl.store(db + i_s * D + o_d, b_db, mask=mask)
|
| 441 |
-
|
| 442 |
-
|
| 443 |
-
def layer_norm_gated_fwd(
|
| 444 |
-
x: torch.Tensor,
|
| 445 |
-
g: torch.Tensor,
|
| 446 |
-
weight: torch.Tensor,
|
| 447 |
-
bias: torch.Tensor,
|
| 448 |
-
activation: str = "swish",
|
| 449 |
-
eps: float = 1e-5,
|
| 450 |
-
residual: torch.Tensor = None,
|
| 451 |
-
out_dtype: torch.dtype = None,
|
| 452 |
-
residual_dtype: torch.dtype = None,
|
| 453 |
-
is_rms_norm: bool = False,
|
| 454 |
-
):
|
| 455 |
-
if residual is not None:
|
| 456 |
-
residual_dtype = residual.dtype
|
| 457 |
-
T, D = x.shape
|
| 458 |
-
if residual is not None:
|
| 459 |
-
assert residual.shape == (T, D)
|
| 460 |
-
if weight is not None:
|
| 461 |
-
assert weight.shape == (D,)
|
| 462 |
-
if bias is not None:
|
| 463 |
-
assert bias.shape == (D,)
|
| 464 |
-
# allocate output
|
| 465 |
-
y = torch.empty_like(x, dtype=x.dtype if out_dtype is None else out_dtype)
|
| 466 |
-
if residual is not None or (residual_dtype is not None and residual_dtype != x.dtype):
|
| 467 |
-
residual_out = torch.empty(T, D, device=x.device, dtype=residual_dtype)
|
| 468 |
-
else:
|
| 469 |
-
residual_out = None
|
| 470 |
-
mean = torch.empty((T,), dtype=torch.float, device=x.device) if not is_rms_norm else None
|
| 471 |
-
rstd = torch.empty((T,), dtype=torch.float, device=x.device)
|
| 472 |
-
# Less than 64KB per feature: enqueue fused kernel
|
| 473 |
-
MAX_FUSED_SIZE = 65536 // x.element_size()
|
| 474 |
-
BD = min(MAX_FUSED_SIZE, triton.next_power_of_2(D))
|
| 475 |
-
if D > BD:
|
| 476 |
-
raise RuntimeError("This layer norm doesn't support feature dim >= 64KB.")
|
| 477 |
-
# heuristics for number of warps
|
| 478 |
-
|
| 479 |
-
if D <= 512:
|
| 480 |
-
# NOTE(tylerr): Avoid excessive recompilation and autotuning by tolerating a larger range
|
| 481 |
-
# of T before recompiling the kernel.
|
| 482 |
-
# NB = triton.cdiv(T, 2048)
|
| 483 |
-
NB = triton.cdiv(T, 2048 * 32)
|
| 484 |
-
|
| 485 |
-
def grid(meta):
|
| 486 |
-
return (triton.cdiv(T, meta["BT"]),)
|
| 487 |
-
|
| 488 |
-
layer_norm_gated_fwd_kernel[grid](
|
| 489 |
-
x=x,
|
| 490 |
-
g=g,
|
| 491 |
-
y=y,
|
| 492 |
-
w=weight,
|
| 493 |
-
b=bias,
|
| 494 |
-
residual=residual,
|
| 495 |
-
residual_out=residual_out,
|
| 496 |
-
mean=mean,
|
| 497 |
-
rstd=rstd,
|
| 498 |
-
eps=eps,
|
| 499 |
-
T=T,
|
| 500 |
-
D=D,
|
| 501 |
-
BD=BD,
|
| 502 |
-
NB=NB,
|
| 503 |
-
ACTIVATION=activation,
|
| 504 |
-
IS_RMS_NORM=is_rms_norm,
|
| 505 |
-
)
|
| 506 |
-
else:
|
| 507 |
-
layer_norm_gated_fwd_kernel1[(T,)](
|
| 508 |
-
x=x,
|
| 509 |
-
g=g,
|
| 510 |
-
y=y,
|
| 511 |
-
w=weight,
|
| 512 |
-
b=bias,
|
| 513 |
-
residual=residual,
|
| 514 |
-
residual_out=residual_out,
|
| 515 |
-
mean=mean,
|
| 516 |
-
rstd=rstd,
|
| 517 |
-
eps=eps,
|
| 518 |
-
D=D,
|
| 519 |
-
BD=BD,
|
| 520 |
-
ACTIVATION=activation,
|
| 521 |
-
IS_RMS_NORM=is_rms_norm,
|
| 522 |
-
)
|
| 523 |
-
# residual_out is None if residual is None and residual_dtype == input_dtype
|
| 524 |
-
return y, mean, rstd, residual_out if residual_out is not None else x
|
| 525 |
-
|
| 526 |
-
|
| 527 |
-
def layer_norm_gated_bwd(
|
| 528 |
-
dy: torch.Tensor,
|
| 529 |
-
x: torch.Tensor,
|
| 530 |
-
g: torch.Tensor,
|
| 531 |
-
weight: torch.Tensor,
|
| 532 |
-
bias: torch.Tensor,
|
| 533 |
-
activation: str = "swish",
|
| 534 |
-
eps: float = 1e-5,
|
| 535 |
-
mean: torch.Tensor = None,
|
| 536 |
-
rstd: torch.Tensor = None,
|
| 537 |
-
dresidual: torch.Tensor = None,
|
| 538 |
-
has_residual: bool = False,
|
| 539 |
-
is_rms_norm: bool = False,
|
| 540 |
-
x_dtype: torch.dtype = None,
|
| 541 |
-
recompute_output: bool = False,
|
| 542 |
-
):
|
| 543 |
-
T, D = x.shape
|
| 544 |
-
assert dy.shape == (T, D)
|
| 545 |
-
if dresidual is not None:
|
| 546 |
-
assert dresidual.shape == (T, D)
|
| 547 |
-
if weight is not None:
|
| 548 |
-
assert weight.shape == (D,)
|
| 549 |
-
if bias is not None:
|
| 550 |
-
assert bias.shape == (D,)
|
| 551 |
-
# allocate output
|
| 552 |
-
dx = torch.empty_like(x) if x_dtype is None else torch.empty(T, D, dtype=x_dtype, device=x.device)
|
| 553 |
-
dg = torch.empty_like(g) if x_dtype is None else torch.empty(T, D, dtype=x_dtype, device=x.device)
|
| 554 |
-
dresidual_in = torch.empty_like(x) if has_residual and dx.dtype != x.dtype else None
|
| 555 |
-
y = torch.empty(T, D, dtype=dy.dtype, device=dy.device) if recompute_output else None
|
| 556 |
-
|
| 557 |
-
# Less than 64KB per feature: enqueue fused kernel
|
| 558 |
-
MAX_FUSED_SIZE = 65536 // x.element_size()
|
| 559 |
-
BD = min(MAX_FUSED_SIZE, triton.next_power_of_2(D))
|
| 560 |
-
if D > BD:
|
| 561 |
-
raise RuntimeError("This layer norm doesn't support feature dim >= 64KB.")
|
| 562 |
-
# cap program count to T so no program is completely idle.
|
| 563 |
-
# without this, high-SM GPUs (e.g. B200, 160 SMs) with small T would
|
| 564 |
-
# launch idle programs whose make_block_ptr offsets exceed the tensor shape.
|
| 565 |
-
NS = min(get_multiprocessor_count(x.device.index), T)
|
| 566 |
-
BS = math.ceil(T / NS)
|
| 567 |
-
|
| 568 |
-
dw = torch.empty((NS, D), dtype=torch.float, device=weight.device) if weight is not None else None
|
| 569 |
-
db = torch.empty((NS, D), dtype=torch.float, device=bias.device) if bias is not None else None
|
| 570 |
-
grid = (NS,)
|
| 571 |
-
|
| 572 |
-
if D <= 512:
|
| 573 |
-
# NOTE(tylerr): Avoid excessive recompilation and autotuning by tolerating a larger range
|
| 574 |
-
# of T before recompiling the kernel.
|
| 575 |
-
# NB = triton.cdiv(T, 2048)
|
| 576 |
-
NB = triton.cdiv(T, 2048 * 32)
|
| 577 |
-
|
| 578 |
-
layer_norm_gated_bwd_kernel[grid](
|
| 579 |
-
x=x,
|
| 580 |
-
g=g,
|
| 581 |
-
w=weight,
|
| 582 |
-
b=bias,
|
| 583 |
-
y=y,
|
| 584 |
-
dy=dy,
|
| 585 |
-
dx=dx,
|
| 586 |
-
dg=dg,
|
| 587 |
-
dw=dw,
|
| 588 |
-
db=db,
|
| 589 |
-
dresidual=dresidual,
|
| 590 |
-
dresidual_in=dresidual_in,
|
| 591 |
-
mean=mean,
|
| 592 |
-
rstd=rstd,
|
| 593 |
-
T=T,
|
| 594 |
-
D=D,
|
| 595 |
-
BS=BS,
|
| 596 |
-
BD=BD,
|
| 597 |
-
NB=NB,
|
| 598 |
-
ACTIVATION=activation,
|
| 599 |
-
IS_RMS_NORM=is_rms_norm,
|
| 600 |
-
STORE_DRESIDUAL=dresidual_in is not None,
|
| 601 |
-
)
|
| 602 |
-
else:
|
| 603 |
-
layer_norm_gated_bwd_kernel1[grid](
|
| 604 |
-
x=x,
|
| 605 |
-
g=g,
|
| 606 |
-
w=weight,
|
| 607 |
-
b=bias,
|
| 608 |
-
y=y,
|
| 609 |
-
dy=dy,
|
| 610 |
-
dx=dx,
|
| 611 |
-
dg=dg,
|
| 612 |
-
dw=dw,
|
| 613 |
-
db=db,
|
| 614 |
-
dresidual=dresidual,
|
| 615 |
-
dresidual_in=dresidual_in,
|
| 616 |
-
mean=mean,
|
| 617 |
-
rstd=rstd,
|
| 618 |
-
T=T,
|
| 619 |
-
D=D,
|
| 620 |
-
BS=BS,
|
| 621 |
-
BD=BD,
|
| 622 |
-
ACTIVATION=activation,
|
| 623 |
-
IS_RMS_NORM=is_rms_norm,
|
| 624 |
-
STORE_DRESIDUAL=dresidual_in is not None,
|
| 625 |
-
)
|
| 626 |
-
dw = dw.sum(0).to(weight.dtype) if weight is not None else None
|
| 627 |
-
db = db.sum(0).to(bias.dtype) if bias is not None else None
|
| 628 |
-
# Don't need to compute dresidual_in separately in this case
|
| 629 |
-
if has_residual and dx.dtype == x.dtype:
|
| 630 |
-
dresidual_in = dx
|
| 631 |
-
return (dx, dg, dw, db, dresidual_in) if not recompute_output else (dx, dg, dw, db, dresidual_in, y)
|
| 632 |
-
|
| 633 |
-
|
| 634 |
-
class LayerNormGatedFunction(torch.autograd.Function):
|
| 635 |
-
@staticmethod
|
| 636 |
-
@input_guard
|
| 637 |
-
def forward(
|
| 638 |
-
ctx,
|
| 639 |
-
x: torch.Tensor,
|
| 640 |
-
g: torch.Tensor,
|
| 641 |
-
weight: torch.Tensor,
|
| 642 |
-
bias: torch.Tensor,
|
| 643 |
-
activation: str,
|
| 644 |
-
residual: torch.Tensor | None = None,
|
| 645 |
-
eps: float = 1e-6,
|
| 646 |
-
prenorm: bool = False,
|
| 647 |
-
residual_in_fp32: bool = False,
|
| 648 |
-
is_rms_norm: bool = False,
|
| 649 |
-
):
|
| 650 |
-
x_shape_og = x.shape
|
| 651 |
-
g_shape_og = g.shape
|
| 652 |
-
# reshape input data into 2D tensor
|
| 653 |
-
x = x.reshape(-1, x.shape[-1])
|
| 654 |
-
g = g.reshape(-1, g.shape[-1])
|
| 655 |
-
if residual is not None:
|
| 656 |
-
assert residual.shape == x_shape_og
|
| 657 |
-
residual = residual.reshape(-1, residual.shape[-1])
|
| 658 |
-
residual_dtype = residual.dtype if residual is not None else (torch.float if residual_in_fp32 else None)
|
| 659 |
-
y, mean, rstd, residual_out = layer_norm_gated_fwd(
|
| 660 |
-
x=x,
|
| 661 |
-
g=g,
|
| 662 |
-
weight=weight,
|
| 663 |
-
bias=bias,
|
| 664 |
-
activation=activation,
|
| 665 |
-
eps=eps,
|
| 666 |
-
residual=residual,
|
| 667 |
-
residual_dtype=residual_dtype,
|
| 668 |
-
is_rms_norm=is_rms_norm,
|
| 669 |
-
)
|
| 670 |
-
ctx.save_for_backward(residual_out, g, weight, bias, mean, rstd)
|
| 671 |
-
ctx.x_shape_og = x_shape_og
|
| 672 |
-
ctx.g_shape_og = g_shape_og
|
| 673 |
-
ctx.activation = activation
|
| 674 |
-
ctx.eps = eps
|
| 675 |
-
ctx.is_rms_norm = is_rms_norm
|
| 676 |
-
ctx.has_residual = residual is not None
|
| 677 |
-
ctx.prenorm = prenorm
|
| 678 |
-
ctx.x_dtype = x.dtype
|
| 679 |
-
y = y.reshape(x_shape_og)
|
| 680 |
-
return y if not prenorm else (y, residual_out.reshape(x_shape_og))
|
| 681 |
-
|
| 682 |
-
@staticmethod
|
| 683 |
-
@input_guard
|
| 684 |
-
def backward(ctx, dy, *args):
|
| 685 |
-
x, g, weight, bias, mean, rstd = ctx.saved_tensors
|
| 686 |
-
dy = dy.reshape(-1, dy.shape[-1])
|
| 687 |
-
assert dy.shape == x.shape
|
| 688 |
-
if ctx.prenorm:
|
| 689 |
-
dresidual = args[0]
|
| 690 |
-
dresidual = dresidual.reshape(-1, dresidual.shape[-1])
|
| 691 |
-
assert dresidual.shape == x.shape
|
| 692 |
-
else:
|
| 693 |
-
dresidual = None
|
| 694 |
-
dx, dg, dw, db, dres_in = layer_norm_gated_bwd(
|
| 695 |
-
dy=dy,
|
| 696 |
-
x=x,
|
| 697 |
-
g=g,
|
| 698 |
-
weight=weight,
|
| 699 |
-
bias=bias,
|
| 700 |
-
activation=ctx.activation,
|
| 701 |
-
eps=ctx.eps,
|
| 702 |
-
mean=mean,
|
| 703 |
-
rstd=rstd,
|
| 704 |
-
dresidual=dresidual,
|
| 705 |
-
has_residual=ctx.has_residual,
|
| 706 |
-
is_rms_norm=ctx.is_rms_norm,
|
| 707 |
-
x_dtype=ctx.x_dtype,
|
| 708 |
-
)
|
| 709 |
-
return (
|
| 710 |
-
dx.reshape(ctx.x_shape_og),
|
| 711 |
-
dg.reshape(ctx.g_shape_og),
|
| 712 |
-
dw,
|
| 713 |
-
db,
|
| 714 |
-
None,
|
| 715 |
-
dres_in.reshape(ctx.x_shape_og) if ctx.has_residual else None,
|
| 716 |
-
None,
|
| 717 |
-
None,
|
| 718 |
-
None,
|
| 719 |
-
None,
|
| 720 |
-
)
|
| 721 |
-
|
| 722 |
-
|
| 723 |
-
class LayerNormGatedLinearFunction(torch.autograd.Function):
|
| 724 |
-
@staticmethod
|
| 725 |
-
@input_guard
|
| 726 |
-
def forward(
|
| 727 |
-
ctx,
|
| 728 |
-
x: torch.Tensor,
|
| 729 |
-
g: torch.Tensor,
|
| 730 |
-
norm_weight: torch.Tensor,
|
| 731 |
-
norm_bias: torch.Tensor,
|
| 732 |
-
linear_weight: torch.Tensor,
|
| 733 |
-
linear_bias: torch.Tensor,
|
| 734 |
-
residual: torch.Tensor | None = None,
|
| 735 |
-
eps: float = 1e-6,
|
| 736 |
-
prenorm: bool = False,
|
| 737 |
-
residual_in_fp32: bool = False,
|
| 738 |
-
is_rms_norm: bool = False,
|
| 739 |
-
):
|
| 740 |
-
x_shape_og = x.shape
|
| 741 |
-
g_shape_og = g.shape
|
| 742 |
-
# reshape input data into 2D tensor
|
| 743 |
-
x = x.reshape(-1, x.shape[-1])
|
| 744 |
-
g = g.reshape(-1, g.shape[-1])
|
| 745 |
-
if residual is not None:
|
| 746 |
-
assert residual.shape == x_shape_og
|
| 747 |
-
residual = residual.reshape(-1, residual.shape[-1])
|
| 748 |
-
residual_dtype = residual.dtype if residual is not None else (torch.float if residual_in_fp32 else None)
|
| 749 |
-
y, mean, rstd, residual_out = layer_norm_gated_fwd(
|
| 750 |
-
x=x,
|
| 751 |
-
g=g,
|
| 752 |
-
weight=norm_weight,
|
| 753 |
-
bias=norm_bias,
|
| 754 |
-
eps=eps,
|
| 755 |
-
residual=residual,
|
| 756 |
-
residual_dtype=residual_dtype,
|
| 757 |
-
is_rms_norm=is_rms_norm,
|
| 758 |
-
)
|
| 759 |
-
y = y.reshape(x_shape_og)
|
| 760 |
-
dtype = torch.get_autocast_gpu_dtype() if torch.is_autocast_enabled() else y.dtype
|
| 761 |
-
linear_weight = linear_weight.to(dtype)
|
| 762 |
-
linear_bias = linear_bias.to(dtype) if linear_bias is not None else None
|
| 763 |
-
out = F.linear(y.to(linear_weight.dtype), linear_weight, linear_bias)
|
| 764 |
-
# We don't store y, will be recomputed in the backward pass to save memory
|
| 765 |
-
ctx.save_for_backward(residual_out, g, norm_weight, norm_bias, linear_weight, mean, rstd)
|
| 766 |
-
ctx.x_shape_og = x_shape_og
|
| 767 |
-
ctx.g_shape_og = g_shape_og
|
| 768 |
-
ctx.eps = eps
|
| 769 |
-
ctx.is_rms_norm = is_rms_norm
|
| 770 |
-
ctx.has_residual = residual is not None
|
| 771 |
-
ctx.prenorm = prenorm
|
| 772 |
-
ctx.x_dtype = x.dtype
|
| 773 |
-
ctx.linear_bias_is_none = linear_bias is None
|
| 774 |
-
return out if not prenorm else (out, residual_out.reshape(x_shape_og))
|
| 775 |
-
|
| 776 |
-
@staticmethod
|
| 777 |
-
@input_guard
|
| 778 |
-
def backward(ctx, dout, *args):
|
| 779 |
-
x, g, norm_weight, norm_bias, linear_weight, mean, rstd = ctx.saved_tensors
|
| 780 |
-
dout = dout.reshape(-1, dout.shape[-1])
|
| 781 |
-
dy = F.linear(dout, linear_weight.t())
|
| 782 |
-
dlinear_bias = None if ctx.linear_bias_is_none else dout.sum(0)
|
| 783 |
-
assert dy.shape == x.shape
|
| 784 |
-
if ctx.prenorm:
|
| 785 |
-
dresidual = args[0]
|
| 786 |
-
dresidual = dresidual.reshape(-1, dresidual.shape[-1])
|
| 787 |
-
assert dresidual.shape == x.shape
|
| 788 |
-
else:
|
| 789 |
-
dresidual = None
|
| 790 |
-
dx, dg, dnorm_weight, dnorm_bias, dres_in, y = layer_norm_gated_bwd(
|
| 791 |
-
dy=dy,
|
| 792 |
-
x=x,
|
| 793 |
-
g=g,
|
| 794 |
-
weight=norm_weight,
|
| 795 |
-
bias=norm_bias,
|
| 796 |
-
eps=ctx.eps,
|
| 797 |
-
mean=mean,
|
| 798 |
-
rstd=rstd,
|
| 799 |
-
dresidual=dresidual,
|
| 800 |
-
has_residual=ctx.has_residual,
|
| 801 |
-
is_rms_norm=ctx.is_rms_norm,
|
| 802 |
-
x_dtype=ctx.x_dtype,
|
| 803 |
-
recompute_output=True,
|
| 804 |
-
)
|
| 805 |
-
dlinear_weight = torch.einsum("bo,bi->oi", dout, y)
|
| 806 |
-
return (
|
| 807 |
-
dx.reshape(ctx.x_shape_og),
|
| 808 |
-
dg.reshape(ctx.g_shape_og),
|
| 809 |
-
dnorm_weight,
|
| 810 |
-
dnorm_bias,
|
| 811 |
-
dlinear_weight,
|
| 812 |
-
dlinear_bias,
|
| 813 |
-
dres_in.reshape(ctx.x_shape_og) if ctx.has_residual else None,
|
| 814 |
-
None,
|
| 815 |
-
None,
|
| 816 |
-
None,
|
| 817 |
-
None,
|
| 818 |
-
)
|
| 819 |
-
|
| 820 |
-
|
| 821 |
-
def layer_norm_gated(
|
| 822 |
-
x: torch.Tensor,
|
| 823 |
-
g: torch.Tensor,
|
| 824 |
-
weight: torch.Tensor,
|
| 825 |
-
bias: torch.Tensor,
|
| 826 |
-
activation: str = "swish",
|
| 827 |
-
residual: torch.Tensor | None = None,
|
| 828 |
-
prenorm: bool = False,
|
| 829 |
-
residual_in_fp32: bool = False,
|
| 830 |
-
eps: float = 1e-6,
|
| 831 |
-
):
|
| 832 |
-
return LayerNormGatedFunction.apply(
|
| 833 |
-
x,
|
| 834 |
-
g,
|
| 835 |
-
weight,
|
| 836 |
-
bias,
|
| 837 |
-
activation,
|
| 838 |
-
residual,
|
| 839 |
-
eps,
|
| 840 |
-
prenorm,
|
| 841 |
-
residual_in_fp32,
|
| 842 |
-
False,
|
| 843 |
-
)
|
| 844 |
-
|
| 845 |
-
|
| 846 |
-
def rms_norm_gated(
|
| 847 |
-
x: torch.Tensor,
|
| 848 |
-
g: torch.Tensor,
|
| 849 |
-
weight: torch.Tensor,
|
| 850 |
-
bias: torch.Tensor,
|
| 851 |
-
activation: str = "swish",
|
| 852 |
-
residual: torch.Tensor | None = None,
|
| 853 |
-
prenorm: bool = False,
|
| 854 |
-
residual_in_fp32: bool = False,
|
| 855 |
-
eps: float = 1e-6,
|
| 856 |
-
):
|
| 857 |
-
return LayerNormGatedFunction.apply(
|
| 858 |
-
x,
|
| 859 |
-
g,
|
| 860 |
-
weight,
|
| 861 |
-
bias,
|
| 862 |
-
activation,
|
| 863 |
-
residual,
|
| 864 |
-
eps,
|
| 865 |
-
prenorm,
|
| 866 |
-
residual_in_fp32,
|
| 867 |
-
True,
|
| 868 |
-
)
|
| 869 |
-
|
| 870 |
-
|
| 871 |
-
def layer_norm_swish_gate_linear(
|
| 872 |
-
x: torch.Tensor,
|
| 873 |
-
g: torch.Tensor,
|
| 874 |
-
norm_weight: torch.Tensor,
|
| 875 |
-
norm_bias: torch.Tensor,
|
| 876 |
-
linear_weight: torch.Tensor,
|
| 877 |
-
linear_bias: torch.Tensor,
|
| 878 |
-
residual: torch.Tensor | None = None,
|
| 879 |
-
prenorm: bool = False,
|
| 880 |
-
residual_in_fp32: bool = False,
|
| 881 |
-
eps: float = 1e-6,
|
| 882 |
-
):
|
| 883 |
-
return LayerNormGatedLinearFunction.apply(
|
| 884 |
-
x,
|
| 885 |
-
g,
|
| 886 |
-
norm_weight,
|
| 887 |
-
norm_bias,
|
| 888 |
-
linear_weight,
|
| 889 |
-
linear_bias,
|
| 890 |
-
residual,
|
| 891 |
-
eps,
|
| 892 |
-
prenorm,
|
| 893 |
-
residual_in_fp32,
|
| 894 |
-
False,
|
| 895 |
-
)
|
| 896 |
-
|
| 897 |
-
|
| 898 |
-
def rms_norm_swish_gate_linear(
|
| 899 |
-
x,
|
| 900 |
-
g: torch.Tensor,
|
| 901 |
-
norm_weight: torch.Tensor,
|
| 902 |
-
norm_bias: torch.Tensor,
|
| 903 |
-
linear_weight: torch.Tensor,
|
| 904 |
-
linear_bias: torch.Tensor,
|
| 905 |
-
residual: torch.Tensor | None = None,
|
| 906 |
-
prenorm: bool = False,
|
| 907 |
-
residual_in_fp32: bool = False,
|
| 908 |
-
eps: float = 1e-6,
|
| 909 |
-
):
|
| 910 |
-
return LayerNormGatedLinearFunction.apply(
|
| 911 |
-
x,
|
| 912 |
-
g,
|
| 913 |
-
norm_weight,
|
| 914 |
-
norm_bias,
|
| 915 |
-
linear_weight,
|
| 916 |
-
linear_bias,
|
| 917 |
-
residual,
|
| 918 |
-
eps,
|
| 919 |
-
prenorm,
|
| 920 |
-
residual_in_fp32,
|
| 921 |
-
True,
|
| 922 |
-
)
|
| 923 |
-
|
| 924 |
-
|
| 925 |
-
class FusedLayerNormGated(nn.Module):
|
| 926 |
-
def __init__(
|
| 927 |
-
self,
|
| 928 |
-
hidden_size: int,
|
| 929 |
-
elementwise_affine: bool = True,
|
| 930 |
-
bias: bool = False,
|
| 931 |
-
activation: str = "swish",
|
| 932 |
-
eps: float = 1e-5,
|
| 933 |
-
device: torch.device | None = None,
|
| 934 |
-
dtype: torch.dtype | None = None,
|
| 935 |
-
) -> FusedLayerNormGated:
|
| 936 |
-
factory_kwargs = {"device": device, "dtype": dtype}
|
| 937 |
-
super().__init__()
|
| 938 |
-
|
| 939 |
-
self.hidden_size = hidden_size
|
| 940 |
-
self.elementwise_affine = elementwise_affine
|
| 941 |
-
self.eps = eps
|
| 942 |
-
self.activation = activation
|
| 943 |
-
|
| 944 |
-
if self.activation not in ["swish", "silu", "sigmoid"]:
|
| 945 |
-
raise ValueError(f"Unsupported activation: {self.activation}")
|
| 946 |
-
|
| 947 |
-
self.register_parameter("weight", None)
|
| 948 |
-
self.register_parameter("bias", None)
|
| 949 |
-
if elementwise_affine:
|
| 950 |
-
self.weight = nn.Parameter(torch.empty(hidden_size, **factory_kwargs))
|
| 951 |
-
if bias:
|
| 952 |
-
self.bias = nn.Parameter(torch.empty(hidden_size, **factory_kwargs))
|
| 953 |
-
|
| 954 |
-
self.reset_parameters()
|
| 955 |
-
|
| 956 |
-
def reset_parameters(self):
|
| 957 |
-
if self.elementwise_affine:
|
| 958 |
-
nn.init.ones_(self.weight)
|
| 959 |
-
if self.bias is not None:
|
| 960 |
-
nn.init.zeros_(self.bias)
|
| 961 |
-
|
| 962 |
-
def __repr__(self) -> str:
|
| 963 |
-
s = f"{self.__class__.__name__}({self.hidden_size}"
|
| 964 |
-
if not self.elementwise_affine:
|
| 965 |
-
s += f", elementwise_affine={self.elementwise_affine}"
|
| 966 |
-
s += f", eps={self.eps}"
|
| 967 |
-
s += f", activation={self.activation}"
|
| 968 |
-
s += ")"
|
| 969 |
-
return s
|
| 970 |
-
|
| 971 |
-
def forward(
|
| 972 |
-
self,
|
| 973 |
-
x: torch.Tensor,
|
| 974 |
-
g: torch.Tensor,
|
| 975 |
-
residual: torch.Tensor | None = None,
|
| 976 |
-
prenorm: bool = False,
|
| 977 |
-
residual_in_fp32: bool = False,
|
| 978 |
-
) -> torch.Tensor:
|
| 979 |
-
return layer_norm_gated(
|
| 980 |
-
x,
|
| 981 |
-
g,
|
| 982 |
-
self.weight,
|
| 983 |
-
self.bias,
|
| 984 |
-
self.activation,
|
| 985 |
-
residual=residual,
|
| 986 |
-
eps=self.eps,
|
| 987 |
-
prenorm=prenorm,
|
| 988 |
-
residual_in_fp32=residual_in_fp32,
|
| 989 |
-
)
|
| 990 |
-
|
| 991 |
-
|
| 992 |
-
class FusedRMSNormGated(nn.Module):
|
| 993 |
-
def __init__(
|
| 994 |
-
self,
|
| 995 |
-
hidden_size: int,
|
| 996 |
-
elementwise_affine: bool = True,
|
| 997 |
-
eps: float = 1e-5,
|
| 998 |
-
activation: str = "swish",
|
| 999 |
-
device: torch.device | None = None,
|
| 1000 |
-
dtype: torch.dtype | None = None,
|
| 1001 |
-
) -> FusedRMSNormGated:
|
| 1002 |
-
factory_kwargs = {"device": device, "dtype": dtype}
|
| 1003 |
-
super().__init__()
|
| 1004 |
-
|
| 1005 |
-
self.hidden_size = hidden_size
|
| 1006 |
-
self.elementwise_affine = elementwise_affine
|
| 1007 |
-
self.eps = eps
|
| 1008 |
-
self.activation = activation
|
| 1009 |
-
|
| 1010 |
-
if self.activation not in ["swish", "silu", "sigmoid"]:
|
| 1011 |
-
raise ValueError(f"Unsupported activation: {self.activation}")
|
| 1012 |
-
|
| 1013 |
-
if elementwise_affine:
|
| 1014 |
-
self.weight = nn.Parameter(torch.empty(hidden_size, **factory_kwargs))
|
| 1015 |
-
else:
|
| 1016 |
-
self.register_parameter("weight", None)
|
| 1017 |
-
self.register_parameter("bias", None)
|
| 1018 |
-
|
| 1019 |
-
self.reset_parameters()
|
| 1020 |
-
|
| 1021 |
-
def reset_parameters(self):
|
| 1022 |
-
if self.elementwise_affine:
|
| 1023 |
-
nn.init.ones_(self.weight)
|
| 1024 |
-
|
| 1025 |
-
def __repr__(self) -> str:
|
| 1026 |
-
s = f"{self.__class__.__name__}({self.hidden_size}"
|
| 1027 |
-
if not self.elementwise_affine:
|
| 1028 |
-
s += f", elementwise_affine={self.elementwise_affine}"
|
| 1029 |
-
s += f", eps={self.eps}"
|
| 1030 |
-
s += f", activation={self.activation}"
|
| 1031 |
-
s += ")"
|
| 1032 |
-
return s
|
| 1033 |
-
|
| 1034 |
-
def forward(
|
| 1035 |
-
self,
|
| 1036 |
-
x: torch.Tensor,
|
| 1037 |
-
g: torch.Tensor,
|
| 1038 |
-
residual: torch.Tensor | None = None,
|
| 1039 |
-
prenorm: bool = False,
|
| 1040 |
-
residual_in_fp32: bool = False,
|
| 1041 |
-
) -> torch.Tensor:
|
| 1042 |
-
return rms_norm_gated(
|
| 1043 |
-
x,
|
| 1044 |
-
g,
|
| 1045 |
-
self.weight,
|
| 1046 |
-
self.bias,
|
| 1047 |
-
self.activation,
|
| 1048 |
-
residual=residual,
|
| 1049 |
-
eps=self.eps,
|
| 1050 |
-
prenorm=prenorm,
|
| 1051 |
-
residual_in_fp32=residual_in_fp32,
|
| 1052 |
-
)
|
| 1053 |
-
|
| 1054 |
-
|
| 1055 |
-
class FusedLayerNormSwishGate(FusedLayerNormGated):
|
| 1056 |
-
def __init__(
|
| 1057 |
-
self,
|
| 1058 |
-
hidden_size: int,
|
| 1059 |
-
elementwise_affine: bool = True,
|
| 1060 |
-
bias: bool = False,
|
| 1061 |
-
eps: float = 1e-5,
|
| 1062 |
-
device: torch.device | None = None,
|
| 1063 |
-
dtype: torch.dtype | None = None,
|
| 1064 |
-
) -> FusedLayerNormSwishGate:
|
| 1065 |
-
super().__init__(
|
| 1066 |
-
hidden_size=hidden_size,
|
| 1067 |
-
elementwise_affine=elementwise_affine,
|
| 1068 |
-
bias=bias,
|
| 1069 |
-
eps=eps,
|
| 1070 |
-
device=device,
|
| 1071 |
-
dtype=dtype,
|
| 1072 |
-
)
|
| 1073 |
-
|
| 1074 |
-
|
| 1075 |
-
class FusedRMSNormSwishGate(FusedRMSNormGated):
|
| 1076 |
-
def __init__(
|
| 1077 |
-
self,
|
| 1078 |
-
hidden_size: int,
|
| 1079 |
-
elementwise_affine: bool = True,
|
| 1080 |
-
eps: float = 1e-5,
|
| 1081 |
-
device: torch.device | None = None,
|
| 1082 |
-
dtype: torch.dtype | None = None,
|
| 1083 |
-
) -> FusedRMSNormSwishGate:
|
| 1084 |
-
super().__init__(
|
| 1085 |
-
hidden_size=hidden_size,
|
| 1086 |
-
elementwise_affine=elementwise_affine,
|
| 1087 |
-
eps=eps,
|
| 1088 |
-
device=device,
|
| 1089 |
-
dtype=dtype,
|
| 1090 |
-
)
|
| 1091 |
-
|
| 1092 |
-
|
| 1093 |
-
class FusedLayerNormGatedLinear(nn.Module):
|
| 1094 |
-
def __init__(
|
| 1095 |
-
self,
|
| 1096 |
-
hidden_size: int,
|
| 1097 |
-
elementwise_affine: bool = True,
|
| 1098 |
-
eps: float = 1e-5,
|
| 1099 |
-
device: torch.device | None = None,
|
| 1100 |
-
dtype: torch.dtype | None = None,
|
| 1101 |
-
) -> FusedLayerNormGatedLinear:
|
| 1102 |
-
factory_kwargs = {"device": device, "dtype": dtype}
|
| 1103 |
-
super().__init__()
|
| 1104 |
-
|
| 1105 |
-
self.hidden_size = hidden_size
|
| 1106 |
-
self.elementwise_affine = elementwise_affine
|
| 1107 |
-
self.eps = eps
|
| 1108 |
-
|
| 1109 |
-
if elementwise_affine:
|
| 1110 |
-
self.weight = nn.Parameter(torch.empty(hidden_size, **factory_kwargs))
|
| 1111 |
-
else:
|
| 1112 |
-
self.register_parameter("weight", None)
|
| 1113 |
-
self.register_parameter("bias", None)
|
| 1114 |
-
|
| 1115 |
-
self.reset_parameters()
|
| 1116 |
-
|
| 1117 |
-
def reset_parameters(self):
|
| 1118 |
-
if self.elementwise_affine:
|
| 1119 |
-
nn.init.ones_(self.weight)
|
| 1120 |
-
|
| 1121 |
-
def __repr__(self) -> str:
|
| 1122 |
-
s = f"{self.__class__.__name__}({self.hidden_size}"
|
| 1123 |
-
if not self.elementwise_affine:
|
| 1124 |
-
s += f", elementwise_affine={self.elementwise_affine}"
|
| 1125 |
-
s += f", eps={self.eps}"
|
| 1126 |
-
s += ")"
|
| 1127 |
-
return s
|
| 1128 |
-
|
| 1129 |
-
def forward(
|
| 1130 |
-
self,
|
| 1131 |
-
x: torch.Tensor,
|
| 1132 |
-
g: torch.Tensor,
|
| 1133 |
-
weight: torch.Tensor | None = None,
|
| 1134 |
-
bias: torch.Tensor | None = None,
|
| 1135 |
-
residual: torch.Tensor | None = None,
|
| 1136 |
-
prenorm: bool = False,
|
| 1137 |
-
residual_in_fp32: bool = False,
|
| 1138 |
-
) -> torch.Tensor:
|
| 1139 |
-
return layer_norm_swish_gate_linear(
|
| 1140 |
-
x,
|
| 1141 |
-
g,
|
| 1142 |
-
self.weight,
|
| 1143 |
-
self.bias,
|
| 1144 |
-
weight,
|
| 1145 |
-
bias,
|
| 1146 |
-
residual=residual,
|
| 1147 |
-
eps=self.eps,
|
| 1148 |
-
prenorm=prenorm,
|
| 1149 |
-
residual_in_fp32=residual_in_fp32,
|
| 1150 |
-
)
|
| 1151 |
-
|
| 1152 |
-
|
| 1153 |
-
class FusedLayerNormSwishGateLinear(FusedLayerNormGatedLinear):
|
| 1154 |
-
def __init__(
|
| 1155 |
-
self,
|
| 1156 |
-
hidden_size: int,
|
| 1157 |
-
elementwise_affine: bool = True,
|
| 1158 |
-
eps: float = 1e-5,
|
| 1159 |
-
device: torch.device | None = None,
|
| 1160 |
-
dtype: torch.dtype | None = None,
|
| 1161 |
-
) -> FusedLayerNormSwishGateLinear:
|
| 1162 |
-
super().__init__(
|
| 1163 |
-
hidden_size=hidden_size,
|
| 1164 |
-
elementwise_affine=elementwise_affine,
|
| 1165 |
-
eps=eps,
|
| 1166 |
-
device=device,
|
| 1167 |
-
dtype=dtype,
|
| 1168 |
-
)
|
| 1169 |
-
|
| 1170 |
-
|
| 1171 |
-
class FusedRMSNormGatedLinear(nn.Module):
|
| 1172 |
-
def __init__(
|
| 1173 |
-
self,
|
| 1174 |
-
hidden_size,
|
| 1175 |
-
elementwise_affine: bool = True,
|
| 1176 |
-
eps: float = 1e-5,
|
| 1177 |
-
device: torch.device | None = None,
|
| 1178 |
-
dtype: torch.dtype | None = None,
|
| 1179 |
-
) -> FusedRMSNormGatedLinear:
|
| 1180 |
-
factory_kwargs = {"device": device, "dtype": dtype}
|
| 1181 |
-
super().__init__()
|
| 1182 |
-
|
| 1183 |
-
self.hidden_size = hidden_size
|
| 1184 |
-
self.elementwise_affine = elementwise_affine
|
| 1185 |
-
self.eps = eps
|
| 1186 |
-
|
| 1187 |
-
self.register_parameter("weight", None)
|
| 1188 |
-
self.register_parameter("bias", None)
|
| 1189 |
-
if elementwise_affine:
|
| 1190 |
-
self.weight = nn.Parameter(torch.empty(hidden_size, **factory_kwargs))
|
| 1191 |
-
|
| 1192 |
-
self.reset_parameters()
|
| 1193 |
-
|
| 1194 |
-
def reset_parameters(self):
|
| 1195 |
-
if self.elementwise_affine:
|
| 1196 |
-
nn.init.ones_(self.weight)
|
| 1197 |
-
|
| 1198 |
-
def __repr__(self) -> str:
|
| 1199 |
-
s = f"{self.__class__.__name__}({self.hidden_size}"
|
| 1200 |
-
if not self.elementwise_affine:
|
| 1201 |
-
s += f", elementwise_affine={self.elementwise_affine}"
|
| 1202 |
-
s += f", eps={self.eps}"
|
| 1203 |
-
s += ")"
|
| 1204 |
-
return s
|
| 1205 |
-
|
| 1206 |
-
def forward(
|
| 1207 |
-
self,
|
| 1208 |
-
x: torch.Tensor,
|
| 1209 |
-
g: torch.Tensor,
|
| 1210 |
-
weight: torch.Tensor | None = None,
|
| 1211 |
-
bias: torch.Tensor | None = None,
|
| 1212 |
-
residual: torch.Tensor | None = None,
|
| 1213 |
-
prenorm: bool = False,
|
| 1214 |
-
residual_in_fp32: bool = False,
|
| 1215 |
-
) -> torch.Tensor:
|
| 1216 |
-
return rms_norm_swish_gate_linear(
|
| 1217 |
-
x,
|
| 1218 |
-
g,
|
| 1219 |
-
self.weight,
|
| 1220 |
-
self.bias,
|
| 1221 |
-
weight,
|
| 1222 |
-
bias,
|
| 1223 |
-
residual=residual,
|
| 1224 |
-
eps=self.eps,
|
| 1225 |
-
prenorm=prenorm,
|
| 1226 |
-
residual_in_fp32=residual_in_fp32,
|
| 1227 |
-
)
|
| 1228 |
-
|
| 1229 |
-
|
| 1230 |
-
class FusedRMSNormSwishGateLinear(FusedRMSNormGatedLinear):
|
| 1231 |
-
def __init__(
|
| 1232 |
-
self,
|
| 1233 |
-
hidden_size: int,
|
| 1234 |
-
elementwise_affine: bool = True,
|
| 1235 |
-
eps: float = 1e-5,
|
| 1236 |
-
device: torch.device | None = None,
|
| 1237 |
-
dtype: torch.dtype | None = None,
|
| 1238 |
-
) -> FusedRMSNormSwishGateLinear:
|
| 1239 |
-
super().__init__(
|
| 1240 |
-
hidden_size=hidden_size,
|
| 1241 |
-
elementwise_affine=elementwise_affine,
|
| 1242 |
-
eps=eps,
|
| 1243 |
-
device=device,
|
| 1244 |
-
dtype=dtype,
|
| 1245 |
-
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
build/{torch-xpu/modules/conv/cp → torch-cuda/modules/grpo}/__init__.py
RENAMED
|
@@ -5,9 +5,7 @@
|
|
| 5 |
# For a list of all contributors, visit:
|
| 6 |
# https://github.com/fla-org/flash-linear-attention/graphs/contributors
|
| 7 |
|
| 8 |
-
from .ops import
|
|
|
|
|
|
|
| 9 |
|
| 10 |
-
__all__ = [
|
| 11 |
-
'CausalConv1dFunctionCP',
|
| 12 |
-
'causal_conv1d_cp',
|
| 13 |
-
]
|
|
|
|
| 5 |
# For a list of all contributors, visit:
|
| 6 |
# https://github.com/fla-org/flash-linear-attention/graphs/contributors
|
| 7 |
|
| 8 |
+
from ...modules.grpo.ops import fused_grpo_loss, grpo_loss_with_old_logps
|
| 9 |
+
|
| 10 |
+
__all__ = ['fused_grpo_loss', 'grpo_loss_with_old_logps']
|
| 11 |
|
|
|
|
|
|
|
|
|
|
|
|
build/torch-cuda/modules/{grpo.py → grpo/ops.py}
RENAMED
|
@@ -6,65 +6,20 @@
|
|
| 6 |
# https://github.com/fla-org/flash-linear-attention/graphs/contributors
|
| 7 |
|
| 8 |
# modified from https://github.com/mdy666/mdy_triton/blob/e0a856347bd988e05e0152332bba35f1d33c5b1f/others/grpo/grpo_loss.ipynb
|
| 9 |
-
#
|
| 10 |
-
|
| 11 |
-
# https://github.com/huggingface/trl/blob/main/trl/trainer/grpo_trainer.py
|
| 12 |
-
"""
|
| 13 |
-
# Get the per-token log probabilities for the completions for the model and the reference model
|
| 14 |
-
def _get_per_token_logps(self, model, input_ids, attention_mask, logits_to_keep):
|
| 15 |
-
# We add 1 to `logits_to_keep` because the last logits of the sequence is later excluded
|
| 16 |
-
logits = model(input_ids=input_ids, attention_mask=attention_mask, logits_to_keep=logits_to_keep + 1).logits
|
| 17 |
-
logits = logits[:, :-1, :] # (B, L-1, V), exclude the last logit: it corresponds to the next token pred
|
| 18 |
-
|
| 19 |
-
input_ids = input_ids[:, -logits_to_keep:]
|
| 20 |
-
# For transformers<=4.48, logits_to_keep argument isn't supported, so here we drop logits ourselves.
|
| 21 |
-
# See https://github.com/huggingface/trl/issues/2770
|
| 22 |
-
logits = logits[:, -logits_to_keep:]
|
| 23 |
-
return selective_log_softmax(logits, input_ids) # compute logprobs for the input tokens
|
| 24 |
-
|
| 25 |
-
def compute_loss(self, model, inputs, return_outputs=False, num_items_in_batch=None):
|
| 26 |
-
if return_outputs:
|
| 27 |
-
raise ValueError("The GRPOTrainer does not support returning outputs")
|
| 28 |
-
# Compute the per-token log probabilities for the model
|
| 29 |
-
|
| 30 |
-
prompt_ids, prompt_mask = inputs["prompt_ids"], inputs["prompt_mask"]
|
| 31 |
-
completion_ids, completion_mask = inputs["completion_ids"], inputs["completion_mask"]
|
| 32 |
-
input_ids = torch.cat([prompt_ids, completion_ids], dim=1)
|
| 33 |
-
attention_mask = torch.cat([prompt_mask, completion_mask], dim=1)
|
| 34 |
-
logits_to_keep = completion_ids.size(1) # we only need to compute the logits for the completion tokens
|
| 35 |
-
|
| 36 |
-
per_token_logps = self._get_per_token_logps(model, input_ids, attention_mask, logits_to_keep)
|
| 37 |
-
|
| 38 |
-
# Compute the KL divergence between the model and the reference model
|
| 39 |
-
ref_per_token_logps = inputs["ref_per_token_logps"]
|
| 40 |
-
per_token_kl = torch.exp(ref_per_token_logps - per_token_logps) - (ref_per_token_logps - per_token_logps) - 1
|
| 41 |
-
|
| 42 |
-
# x - x.detach() allows for preserving gradients from x
|
| 43 |
-
advantages = inputs["advantages"]
|
| 44 |
-
per_token_loss = torch.exp(per_token_logps - per_token_logps.detach()) * advantages.unsqueeze(1)
|
| 45 |
-
per_token_loss = -(per_token_loss - self.beta * per_token_kl)
|
| 46 |
-
loss = ((per_token_loss * completion_mask).sum(dim=1) / completion_mask.sum(dim=1)).mean()
|
| 47 |
-
|
| 48 |
-
# Log the metrics
|
| 49 |
-
completion_length = self.accelerator.gather_for_metrics(completion_mask.sum(1)).float().mean().item()
|
| 50 |
-
self._metrics["completion_length"].append(completion_length)
|
| 51 |
-
|
| 52 |
-
mean_kl = ((per_token_kl * completion_mask).sum(dim=1) / completion_mask.sum(dim=1)).mean()
|
| 53 |
-
self._metrics["kl"].append(self.accelerator.gather_for_metrics(mean_kl).mean().item())
|
| 54 |
-
|
| 55 |
-
return loss
|
| 56 |
-
"""
|
| 57 |
|
| 58 |
|
| 59 |
import torch
|
| 60 |
import triton
|
| 61 |
import triton.language as tl
|
| 62 |
|
| 63 |
-
from ..
|
| 64 |
-
from ..ops.utils.op import exp, log
|
| 65 |
-
from ..utils import IS_AMD, autotune_cache_kwargs, input_guard
|
| 66 |
|
| 67 |
NUM_WARPS_AUTOTUNE = [4, 8, 16] if IS_AMD else [4, 8, 16, 32]
|
|
|
|
|
|
|
| 68 |
|
| 69 |
|
| 70 |
@triton.autotune(
|
|
@@ -72,7 +27,7 @@ NUM_WARPS_AUTOTUNE = [4, 8, 16] if IS_AMD else [4, 8, 16, 32]
|
|
| 72 |
triton.Config({'BLOCK_SIZE': BLOCK_SIZE}, num_warps=NUM_WARPS, num_stages=NUM_STAGES)
|
| 73 |
for BLOCK_SIZE in [1024, 2048, 4096, 8192]
|
| 74 |
for NUM_WARPS in NUM_WARPS_AUTOTUNE
|
| 75 |
-
for NUM_STAGES in
|
| 76 |
],
|
| 77 |
key=['B', 'N'],
|
| 78 |
**autotune_cache_kwargs,
|
|
@@ -198,8 +153,7 @@ def grpo_bwd_kernel(
|
|
| 198 |
tl.debug_barrier()
|
| 199 |
logp = x - lse
|
| 200 |
|
| 201 |
-
dlogp = (beta * (-1.0 * exp(ref_logp - logp) + 1)
|
| 202 |
-
- advantage) * dloss
|
| 203 |
|
| 204 |
for start_n in tl.range(0, N, BLOCK_SIZE):
|
| 205 |
cols = start_n + base_cols
|
|
@@ -251,7 +205,10 @@ class GrpoLoss(torch.autograd.Function):
|
|
| 251 |
lse_ptr=lse,
|
| 252 |
beta=beta,
|
| 253 |
save_kl=save_kl,
|
| 254 |
-
B=B,
|
|
|
|
|
|
|
|
|
|
| 255 |
start_idx=input_ids_start_index,
|
| 256 |
)
|
| 257 |
ctx.beta = beta
|
|
@@ -263,7 +220,6 @@ class GrpoLoss(torch.autograd.Function):
|
|
| 263 |
@input_guard
|
| 264 |
@staticmethod
|
| 265 |
def backward(ctx, dloss):
|
| 266 |
-
# The grad of logits comes from two parts, the reward part and the kl part
|
| 267 |
lse, logits, input_ids, advantages, completion_mask = ctx.saved_tensors
|
| 268 |
inplace = ctx.inplace
|
| 269 |
B, L_ADD_1, N = ctx.input_shape
|
|
@@ -286,46 +242,52 @@ class GrpoLoss(torch.autograd.Function):
|
|
| 286 |
completion_mask_ptr=completion_mask,
|
| 287 |
lse_ptr=lse,
|
| 288 |
beta=ctx.beta,
|
| 289 |
-
B=B,
|
| 290 |
-
|
|
|
|
| 291 |
start_idx=input_ids_start_index,
|
|
|
|
| 292 |
)
|
| 293 |
-
#
|
| 294 |
-
# and therefore its gradient should be set to 0
|
| 295 |
dlogits[:, -1, :].fill_(0.0)
|
| 296 |
return dlogits.view(*ctx.input_shape), None, None, None, None, None, None, None
|
| 297 |
|
| 298 |
|
| 299 |
-
@dispatch
|
| 300 |
-
def fused_grpo_loss(
|
| 301 |
-
|
| 302 |
-
|
| 303 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 304 |
|
| 305 |
Args:
|
| 306 |
-
|
| 307 |
-
|
| 308 |
-
|
| 309 |
-
|
| 310 |
-
|
| 311 |
-
|
| 312 |
-
|
| 313 |
-
|
| 314 |
-
|
| 315 |
-
|
| 316 |
-
|
| 317 |
-
|
| 318 |
-
|
| 319 |
-
|
| 320 |
-
|
| 321 |
-
|
| 322 |
-
|
| 323 |
-
|
| 324 |
-
|
| 325 |
-
|
| 326 |
-
|
| 327 |
-
logits = get_per_token_logits(model, prompt_completion_ids, attention_mask, logits_to_keep)
|
| 328 |
-
'''
|
| 329 |
out = GrpoLoss.apply(logits, ref_logp, input_ids, advantages, beta, completion_mask, save_kl, inplace)
|
| 330 |
if not save_kl:
|
| 331 |
return out
|
|
@@ -356,7 +318,8 @@ def grpo_loss_torch(logits, ref_logp, input_ids, advantages, beta=0.1, completio
|
|
| 356 |
return per_token_loss if not save_kl else (per_token_loss, per_token_kl)
|
| 357 |
|
| 358 |
|
| 359 |
-
|
|
|
|
| 360 |
def grpo_loss_with_old_logps(
|
| 361 |
logps: torch.Tensor,
|
| 362 |
ref_logps: torch.Tensor,
|
|
@@ -367,55 +330,52 @@ def grpo_loss_with_old_logps(
|
|
| 367 |
beta: float = 0.2,
|
| 368 |
epsilon: float = 0.2,
|
| 369 |
):
|
| 370 |
-
"""
|
| 371 |
-
Compute the GRPO (Group Relative Policy Optimization) loss.
|
| 372 |
|
| 373 |
Args:
|
| 374 |
-
logps (torch.Tensor):
|
| 375 |
-
|
| 376 |
-
|
| 377 |
-
|
| 378 |
-
|
| 379 |
-
|
| 380 |
-
|
| 381 |
-
|
| 382 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 383 |
|
| 384 |
Returns:
|
| 385 |
-
torch.Tensor:
|
|
|
|
| 386 |
"""
|
| 387 |
B = logps.shape[0]
|
| 388 |
assert B > 1, "Batch * Num generations should be greater than 1"
|
| 389 |
|
| 390 |
rewards_shaped = rewards.view(-1, B) # B,num_generations
|
| 391 |
-
advantages = (rewards_shaped - rewards_shaped.mean(dim=1, keepdim=True)) /
|
| 392 |
-
(rewards_shaped.std(dim=1, keepdim=True) + 1e-8)
|
| 393 |
advantages = advantages.view(-1) # B*num_generations
|
| 394 |
-
# Calculate the per - token KL divergence
|
| 395 |
per_token_kl = torch.exp(ref_logps - logps) - (ref_logps - logps) - 1
|
| 396 |
|
| 397 |
-
# Calculate the ratio of probabilities (importance weights)
|
| 398 |
-
# Importance weights are calculated as exp(log_pi_theta - log_pi_theta_old)
|
| 399 |
importance_weights = torch.exp(logps - old_logps)
|
| 400 |
|
| 401 |
-
# Clip the importance weights to the range [1 - epsilon, 1 + epsilon]
|
| 402 |
importance_weights_clipped = torch.clamp(importance_weights, 1 - epsilon, 1 + epsilon)
|
| 403 |
|
| 404 |
-
# Create a completion mask. It checks which positions are valid based on logits_to_keep
|
| 405 |
completion_mask = torch.arange(logits_to_keep, device=logps.device)[None, :] >= 0
|
| 406 |
|
| 407 |
-
|
| 408 |
-
completion_mask = completion_mask & pad_mask # Ensure matching shape
|
| 409 |
|
| 410 |
-
# Add an extra dimension to advantages to match the shape for element - wise multiplication
|
| 411 |
advantages = advantages.unsqueeze(1)
|
| 412 |
|
| 413 |
-
|
| 414 |
-
|
| 415 |
-
|
| 416 |
-
importance_weights_clipped) - beta * per_token_kl) * completion_mask
|
| 417 |
|
| 418 |
-
|
| 419 |
-
loss = -token_loss.sum() / completion_mask.sum()
|
| 420 |
|
| 421 |
return loss
|
|
|
|
| 6 |
# https://github.com/fla-org/flash-linear-attention/graphs/contributors
|
| 7 |
|
| 8 |
# modified from https://github.com/mdy666/mdy_triton/blob/e0a856347bd988e05e0152332bba35f1d33c5b1f/others/grpo/grpo_loss.ipynb
|
| 9 |
+
# loss reference: https://github.com/huggingface/trl/blob/main/trl/trainer/grpo_trainer.py
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 10 |
|
| 11 |
|
| 12 |
import torch
|
| 13 |
import triton
|
| 14 |
import triton.language as tl
|
| 15 |
|
| 16 |
+
from ...backends import dispatch
|
| 17 |
+
from ...ops.utils.op import exp, log
|
| 18 |
+
from ...utils import IS_AMD, IS_INTEL, IS_NPU, autotune_cache_kwargs, input_guard
|
| 19 |
|
| 20 |
NUM_WARPS_AUTOTUNE = [4, 8, 16] if IS_AMD else [4, 8, 16, 32]
|
| 21 |
+
# single-stage pipelining avoids Intel/XPU correctness failures with cold memory.
|
| 22 |
+
NUM_STAGES_AUTOTUNE = [1] if IS_INTEL else [1, 2, 4]
|
| 23 |
|
| 24 |
|
| 25 |
@triton.autotune(
|
|
|
|
| 27 |
triton.Config({'BLOCK_SIZE': BLOCK_SIZE}, num_warps=NUM_WARPS, num_stages=NUM_STAGES)
|
| 28 |
for BLOCK_SIZE in [1024, 2048, 4096, 8192]
|
| 29 |
for NUM_WARPS in NUM_WARPS_AUTOTUNE
|
| 30 |
+
for NUM_STAGES in NUM_STAGES_AUTOTUNE
|
| 31 |
],
|
| 32 |
key=['B', 'N'],
|
| 33 |
**autotune_cache_kwargs,
|
|
|
|
| 153 |
tl.debug_barrier()
|
| 154 |
logp = x - lse
|
| 155 |
|
| 156 |
+
dlogp = (beta * (-1.0 * exp(ref_logp - logp) + 1) - advantage) * dloss
|
|
|
|
| 157 |
|
| 158 |
for start_n in tl.range(0, N, BLOCK_SIZE):
|
| 159 |
cols = start_n + base_cols
|
|
|
|
| 205 |
lse_ptr=lse,
|
| 206 |
beta=beta,
|
| 207 |
save_kl=save_kl,
|
| 208 |
+
B=B,
|
| 209 |
+
M=M,
|
| 210 |
+
N=N,
|
| 211 |
+
L=L,
|
| 212 |
start_idx=input_ids_start_index,
|
| 213 |
)
|
| 214 |
ctx.beta = beta
|
|
|
|
| 220 |
@input_guard
|
| 221 |
@staticmethod
|
| 222 |
def backward(ctx, dloss):
|
|
|
|
| 223 |
lse, logits, input_ids, advantages, completion_mask = ctx.saved_tensors
|
| 224 |
inplace = ctx.inplace
|
| 225 |
B, L_ADD_1, N = ctx.input_shape
|
|
|
|
| 242 |
completion_mask_ptr=completion_mask,
|
| 243 |
lse_ptr=lse,
|
| 244 |
beta=ctx.beta,
|
| 245 |
+
B=B,
|
| 246 |
+
N=N,
|
| 247 |
+
L=L,
|
| 248 |
start_idx=input_ids_start_index,
|
| 249 |
+
BLOCK_SIZE=BN,
|
| 250 |
)
|
| 251 |
+
# the final token has no loss contribution, so its gradient is zero.
|
|
|
|
| 252 |
dlogits[:, -1, :].fill_(0.0)
|
| 253 |
return dlogits.view(*ctx.input_shape), None, None, None, None, None, None, None
|
| 254 |
|
| 255 |
|
| 256 |
+
@dispatch
|
| 257 |
+
def fused_grpo_loss(
|
| 258 |
+
logits,
|
| 259 |
+
ref_logp,
|
| 260 |
+
input_ids,
|
| 261 |
+
advantages,
|
| 262 |
+
beta=0.1,
|
| 263 |
+
completion_mask=None,
|
| 264 |
+
save_kl=False,
|
| 265 |
+
inplace=False,
|
| 266 |
+
) -> torch.Tensor | tuple[torch.Tensor, torch.Tensor]:
|
| 267 |
+
"""Compute per-token GRPO loss from completion logits.
|
| 268 |
|
| 269 |
Args:
|
| 270 |
+
logits (torch.Tensor):
|
| 271 |
+
Model logits of shape `[B, L + 1, V]`; the final token is excluded from the loss.
|
| 272 |
+
ref_logp (torch.Tensor):
|
| 273 |
+
Reference model log probabilities of shape `[B, L]` for the sampled completion tokens.
|
| 274 |
+
input_ids (torch.Tensor):
|
| 275 |
+
Prompt and completion token IDs of shape `[B, K + L]`.
|
| 276 |
+
advantages (torch.Tensor):
|
| 277 |
+
Per-sequence advantages of shape `[B]`.
|
| 278 |
+
beta (float, Optional):
|
| 279 |
+
KL penalty coefficient. Default: 0.1.
|
| 280 |
+
completion_mask (torch.Tensor, Optional):
|
| 281 |
+
Mask of shape `[B, L]`; masked tokens have zero loss and gradient. Default: `None`.
|
| 282 |
+
save_kl (bool, Optional):
|
| 283 |
+
Whether to also return the per-token KL penalty. Default: `False`.
|
| 284 |
+
inplace (bool, Optional):
|
| 285 |
+
Whether backward may overwrite logits with gradients. Default: `False`.
|
| 286 |
+
|
| 287 |
+
Returns:
|
| 288 |
+
torch.Tensor | tuple[torch.Tensor, torch.Tensor]:
|
| 289 |
+
Per-token loss of shape `[B, L]`, with a separate KL tensor when `save_kl=True`.
|
| 290 |
+
"""
|
|
|
|
|
|
|
| 291 |
out = GrpoLoss.apply(logits, ref_logp, input_ids, advantages, beta, completion_mask, save_kl, inplace)
|
| 292 |
if not save_kl:
|
| 293 |
return out
|
|
|
|
| 318 |
return per_token_loss if not save_kl else (per_token_loss, per_token_kl)
|
| 319 |
|
| 320 |
|
| 321 |
+
# keep this path eager on NPU to avoid an Inductor miscompile.
|
| 322 |
+
@torch.compile(fullgraph=True, disable=IS_NPU)
|
| 323 |
def grpo_loss_with_old_logps(
|
| 324 |
logps: torch.Tensor,
|
| 325 |
ref_logps: torch.Tensor,
|
|
|
|
| 330 |
beta: float = 0.2,
|
| 331 |
epsilon: float = 0.2,
|
| 332 |
):
|
| 333 |
+
"""Compute clipped GRPO loss using current, reference and old-policy log probabilities.
|
|
|
|
| 334 |
|
| 335 |
Args:
|
| 336 |
+
logps (torch.Tensor):
|
| 337 |
+
Current policy log probabilities of shape `[B, T]`.
|
| 338 |
+
ref_logps (torch.Tensor):
|
| 339 |
+
Reference policy log probabilities of shape `[B, T]`.
|
| 340 |
+
old_logps (torch.Tensor):
|
| 341 |
+
Old policy log probabilities of shape `[B, T]`.
|
| 342 |
+
pad_mask (torch.Tensor):
|
| 343 |
+
Boolean mask selecting completion tokens of shape `[B, T]`.
|
| 344 |
+
logits_to_keep (int):
|
| 345 |
+
Number of completion tokens, equal to `T`.
|
| 346 |
+
rewards (torch.Tensor):
|
| 347 |
+
Per-sequence rewards used to normalize advantages.
|
| 348 |
+
beta (float, Optional):
|
| 349 |
+
KL penalty coefficient. Default: 0.2.
|
| 350 |
+
epsilon (float, Optional):
|
| 351 |
+
Clipping range around an importance weight of one. Default: 0.2.
|
| 352 |
|
| 353 |
Returns:
|
| 354 |
+
torch.Tensor:
|
| 355 |
+
Scalar loss averaged over valid completion tokens.
|
| 356 |
"""
|
| 357 |
B = logps.shape[0]
|
| 358 |
assert B > 1, "Batch * Num generations should be greater than 1"
|
| 359 |
|
| 360 |
rewards_shaped = rewards.view(-1, B) # B,num_generations
|
| 361 |
+
advantages = (rewards_shaped - rewards_shaped.mean(dim=1, keepdim=True)) / (rewards_shaped.std(dim=1, keepdim=True) + 1e-8)
|
|
|
|
| 362 |
advantages = advantages.view(-1) # B*num_generations
|
|
|
|
| 363 |
per_token_kl = torch.exp(ref_logps - logps) - (ref_logps - logps) - 1
|
| 364 |
|
|
|
|
|
|
|
| 365 |
importance_weights = torch.exp(logps - old_logps)
|
| 366 |
|
|
|
|
| 367 |
importance_weights_clipped = torch.clamp(importance_weights, 1 - epsilon, 1 + epsilon)
|
| 368 |
|
|
|
|
| 369 |
completion_mask = torch.arange(logits_to_keep, device=logps.device)[None, :] >= 0
|
| 370 |
|
| 371 |
+
completion_mask = completion_mask & pad_mask
|
|
|
|
| 372 |
|
|
|
|
| 373 |
advantages = advantages.unsqueeze(1)
|
| 374 |
|
| 375 |
+
token_loss = -(
|
| 376 |
+
torch.min(advantages * importance_weights, advantages * importance_weights_clipped) - beta * per_token_kl
|
| 377 |
+
) * completion_mask
|
|
|
|
| 378 |
|
| 379 |
+
loss = token_loss.sum() / completion_mask.sum()
|
|
|
|
| 380 |
|
| 381 |
return loss
|
build/torch-cuda/modules/l2warp.py
CHANGED
|
@@ -39,13 +39,12 @@ class L2Wrap(torch.autograd.Function):
|
|
| 39 |
return loss
|
| 40 |
|
| 41 |
@staticmethod
|
| 42 |
-
def backward(ctx,
|
| 43 |
maxx, ids = ctx.saved_tensors
|
| 44 |
-
|
| 45 |
-
#
|
| 46 |
-
|
| 47 |
-
|
| 48 |
-
return grad_output, glogits, None
|
| 49 |
|
| 50 |
|
| 51 |
l2_warp = L2Wrap.apply
|
|
|
|
| 39 |
return loss
|
| 40 |
|
| 41 |
@staticmethod
|
| 42 |
+
def backward(ctx, dloss: torch.Tensor):
|
| 43 |
maxx, ids = ctx.saved_tensors
|
| 44 |
+
dlogits = torch.zeros(ctx.logits_shape, device=dloss.device, dtype=maxx.dtype)
|
| 45 |
+
# scale before scattering to avoid another full-size logits allocation
|
| 46 |
+
dlogits.scatter_(-1, ids, (maxx * dloss).to(maxx.dtype))
|
| 47 |
+
return dloss, dlogits, None
|
|
|
|
| 48 |
|
| 49 |
|
| 50 |
l2_warp = L2Wrap.apply
|
build/torch-cuda/modules/{conv/long_conv.py → long_conv.py}
RENAMED
|
@@ -13,7 +13,13 @@ import torch.nn.functional as F
|
|
| 13 |
from einops import rearrange
|
| 14 |
|
| 15 |
|
| 16 |
-
def fft_conv(
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 17 |
seqlen = u.shape[-1]
|
| 18 |
fft_size = 2 * seqlen
|
| 19 |
k_f = torch.fft.rfft(k, n=fft_size) / fft_size
|
|
@@ -37,60 +43,52 @@ def fft_conv(u, k, dropout_mask, gelu=True, k_rev=None):
|
|
| 37 |
|
| 38 |
class LongConvolution(nn.Module):
|
| 39 |
"""
|
| 40 |
-
|
| 41 |
-
filter of length max_len.
|
| 42 |
-
The filter is learned during training and is applied using FFT convolution.
|
| 43 |
|
| 44 |
Args:
|
| 45 |
-
hidden_size (int):
|
| 46 |
-
|
|
|
|
|
|
|
| 47 |
|
| 48 |
Returns:
|
| 49 |
-
y
|
|
|
|
| 50 |
"""
|
| 51 |
|
| 52 |
-
def __init__(
|
| 53 |
-
self,
|
| 54 |
-
hidden_size: int,
|
| 55 |
-
max_len: int,
|
| 56 |
-
**kwargs,
|
| 57 |
-
):
|
| 58 |
-
"""
|
| 59 |
-
Initializes the LongConvolution module.
|
| 60 |
-
Args:
|
| 61 |
-
hidden_size (int): The number of expected features in the input and output.
|
| 62 |
-
max_len (int): The maximum sequence length.
|
| 63 |
-
"""
|
| 64 |
super().__init__()
|
| 65 |
self.hidden_size = hidden_size
|
| 66 |
self.filter = nn.Parameter(torch.randn(self.hidden_size, max_len), requires_grad=True)
|
| 67 |
|
| 68 |
-
def forward(self, x: torch.Tensor, *args, **kwargs):
|
| 69 |
"""
|
| 70 |
-
Applies the LongConvolution operation on the input tensor.
|
| 71 |
Args:
|
| 72 |
-
x
|
|
|
|
|
|
|
| 73 |
Returns:
|
| 74 |
-
y
|
|
|
|
| 75 |
"""
|
| 76 |
x = x.transpose(1, 2)
|
| 77 |
-
y = fft_conv(x, self.filter, dropout_mask=None, gelu=False)
|
| 78 |
y = y.transpose(1, 2)
|
| 79 |
return y.to(dtype=x.dtype)
|
| 80 |
|
| 81 |
|
| 82 |
class PositionalEmbedding(nn.Module):
|
| 83 |
-
def __init__(self, emb_dim: int, seq_len: int, **kwargs):
|
| 84 |
"""Complex exponential positional embeddings for implicit long convolution filters."""
|
| 85 |
super().__init__()
|
| 86 |
|
| 87 |
self.seq_len = seq_len
|
| 88 |
-
#
|
| 89 |
t = torch.linspace(0, 1, self.seq_len)[None, :, None] # 1, L, 1
|
| 90 |
|
| 91 |
if emb_dim > 1:
|
| 92 |
bands = (emb_dim - 1) // 2
|
| 93 |
-
#
|
| 94 |
t_rescaled = torch.linspace(0, seq_len - 1, seq_len)[None, :, None]
|
| 95 |
w = 2 * math.pi * t_rescaled / seq_len # 1, L, 1
|
| 96 |
|
|
@@ -99,7 +97,7 @@ class PositionalEmbedding(nn.Module):
|
|
| 99 |
z = torch.cat([t, z.real, z.imag], dim=-1)
|
| 100 |
self.z = nn.Parameter(z, requires_grad=False)
|
| 101 |
|
| 102 |
-
def forward(self, L):
|
| 103 |
return self.z[:, :L]
|
| 104 |
|
| 105 |
|
|
@@ -112,61 +110,45 @@ class ImplicitLongConvolution(nn.Module):
|
|
| 112 |
The number of expected features in the input and output.
|
| 113 |
max_len (int):
|
| 114 |
The maximum sequence length.
|
| 115 |
-
d_emb (
|
| 116 |
The dimension of the positional embeddings. Must be odd and greater or equal to 3 (time, sine and cosine).
|
| 117 |
-
|
| 118 |
-
d_hidden (
|
| 119 |
-
The number of features in the hidden layer of the MLP.
|
| 120 |
|
| 121 |
Attributes:
|
| 122 |
-
pos_emb (
|
| 123 |
-
|
| 124 |
-
|
|
|
|
| 125 |
"""
|
| 126 |
|
| 127 |
-
def __init__(
|
| 128 |
-
self,
|
| 129 |
-
hidden_size: int,
|
| 130 |
-
max_len: int,
|
| 131 |
-
d_emb: int = 3,
|
| 132 |
-
d_hidden: int = 16,
|
| 133 |
-
**kwargs,
|
| 134 |
-
):
|
| 135 |
-
"""
|
| 136 |
-
Long convolution with implicit filter parameterized by an MLP.
|
| 137 |
-
|
| 138 |
-
|
| 139 |
-
"""
|
| 140 |
super().__init__()
|
| 141 |
self.hidden_size = hidden_size
|
| 142 |
self.d_emb = d_emb
|
| 143 |
|
| 144 |
-
assert (
|
| 145 |
-
|
| 146 |
-
), "d_emb must be odd and greater or equal to 3 (time, sine and cosine)"
|
| 147 |
-
self.pos_emb = PositionalEmbedding(d_emb, max_len)
|
| 148 |
|
| 149 |
-
|
| 150 |
-
self.mlp = nn.Sequential(
|
| 151 |
-
nn.Linear(d_emb, d_hidden),
|
| 152 |
-
torch.nn.ReLU(),
|
| 153 |
-
nn.Linear(d_hidden, hidden_size),
|
| 154 |
-
)
|
| 155 |
|
| 156 |
-
def filter(self, seq_len: int, *args, **kwargs):
|
| 157 |
return self.mlp(self.pos_emb(seq_len)).transpose(1, 2)
|
| 158 |
|
| 159 |
-
def forward(self, x: torch.Tensor, *args, **kwargs):
|
| 160 |
"""
|
| 161 |
Args:
|
| 162 |
-
x
|
|
|
|
| 163 |
|
| 164 |
Returns:
|
| 165 |
-
y
|
|
|
|
| 166 |
"""
|
| 167 |
x = x.transpose(1, 2)
|
| 168 |
k = self.filter(x.shape[-1])
|
| 169 |
-
y = fft_conv(x, k, dropout_mask=None, gelu=False)
|
| 170 |
|
| 171 |
y = y.transpose(1, 2)
|
| 172 |
return y.to(dtype=x.dtype)
|
|
|
|
| 13 |
from einops import rearrange
|
| 14 |
|
| 15 |
|
| 16 |
+
def fft_conv(
|
| 17 |
+
u: torch.Tensor,
|
| 18 |
+
k: torch.Tensor,
|
| 19 |
+
dropout_mask: torch.Tensor | None,
|
| 20 |
+
gelu: bool = True,
|
| 21 |
+
k_rev: torch.Tensor | None = None,
|
| 22 |
+
) -> torch.Tensor:
|
| 23 |
seqlen = u.shape[-1]
|
| 24 |
fft_size = 2 * seqlen
|
| 25 |
k_f = torch.fft.rfft(k, n=fft_size) / fft_size
|
|
|
|
| 43 |
|
| 44 |
class LongConvolution(nn.Module):
|
| 45 |
"""
|
| 46 |
+
Apply FFT convolution with a learned filter of length max_len.
|
|
|
|
|
|
|
| 47 |
|
| 48 |
Args:
|
| 49 |
+
hidden_size (int):
|
| 50 |
+
The number of expected features in the input and output.
|
| 51 |
+
max_len (int):
|
| 52 |
+
The maximum sequence length.
|
| 53 |
|
| 54 |
Returns:
|
| 55 |
+
y (torch.Tensor):
|
| 56 |
+
Output of shape [batch_size, seq_len, hidden_size].
|
| 57 |
"""
|
| 58 |
|
| 59 |
+
def __init__(self, hidden_size: int, max_len: int, **kwargs) -> None:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 60 |
super().__init__()
|
| 61 |
self.hidden_size = hidden_size
|
| 62 |
self.filter = nn.Parameter(torch.randn(self.hidden_size, max_len), requires_grad=True)
|
| 63 |
|
| 64 |
+
def forward(self, x: torch.Tensor, *args, **kwargs) -> torch.Tensor:
|
| 65 |
"""
|
|
|
|
| 66 |
Args:
|
| 67 |
+
x (torch.Tensor):
|
| 68 |
+
Input of shape [batch_size, seq_len, hidden_size].
|
| 69 |
+
|
| 70 |
Returns:
|
| 71 |
+
y (torch.Tensor):
|
| 72 |
+
Output of shape [batch_size, seq_len, hidden_size].
|
| 73 |
"""
|
| 74 |
x = x.transpose(1, 2)
|
| 75 |
+
y = fft_conv(u=x, k=self.filter, dropout_mask=None, gelu=False)
|
| 76 |
y = y.transpose(1, 2)
|
| 77 |
return y.to(dtype=x.dtype)
|
| 78 |
|
| 79 |
|
| 80 |
class PositionalEmbedding(nn.Module):
|
| 81 |
+
def __init__(self, emb_dim: int, seq_len: int, **kwargs) -> None:
|
| 82 |
"""Complex exponential positional embeddings for implicit long convolution filters."""
|
| 83 |
super().__init__()
|
| 84 |
|
| 85 |
self.seq_len = seq_len
|
| 86 |
+
# the time embedding fed to the filters is normalized so that t_f = 1
|
| 87 |
t = torch.linspace(0, 1, self.seq_len)[None, :, None] # 1, L, 1
|
| 88 |
|
| 89 |
if emb_dim > 1:
|
| 90 |
bands = (emb_dim - 1) // 2
|
| 91 |
+
# use integer time steps for the complex exponential embeddings
|
| 92 |
t_rescaled = torch.linspace(0, seq_len - 1, seq_len)[None, :, None]
|
| 93 |
w = 2 * math.pi * t_rescaled / seq_len # 1, L, 1
|
| 94 |
|
|
|
|
| 97 |
z = torch.cat([t, z.real, z.imag], dim=-1)
|
| 98 |
self.z = nn.Parameter(z, requires_grad=False)
|
| 99 |
|
| 100 |
+
def forward(self, L: int) -> torch.Tensor:
|
| 101 |
return self.z[:, :L]
|
| 102 |
|
| 103 |
|
|
|
|
| 110 |
The number of expected features in the input and output.
|
| 111 |
max_len (int):
|
| 112 |
The maximum sequence length.
|
| 113 |
+
d_emb (int, Optional):
|
| 114 |
The dimension of the positional embeddings. Must be odd and greater or equal to 3 (time, sine and cosine).
|
| 115 |
+
Default: 3.
|
| 116 |
+
d_hidden (int, Optional):
|
| 117 |
+
The number of features in the hidden layer of the MLP. Default: 16.
|
| 118 |
|
| 119 |
Attributes:
|
| 120 |
+
pos_emb (PositionalEmbedding):
|
| 121 |
+
The positional embedding layer.
|
| 122 |
+
mlp (nn.Sequential):
|
| 123 |
+
The MLP that parameterizes the implicit filter.
|
| 124 |
"""
|
| 125 |
|
| 126 |
+
def __init__(self, hidden_size: int, max_len: int, d_emb: int = 3, d_hidden: int = 16, **kwargs) -> None:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 127 |
super().__init__()
|
| 128 |
self.hidden_size = hidden_size
|
| 129 |
self.d_emb = d_emb
|
| 130 |
|
| 131 |
+
assert d_emb % 2 != 0 and d_emb >= 3, "d_emb must be odd and greater or equal to 3 (time, sine and cosine)"
|
| 132 |
+
self.pos_emb = PositionalEmbedding(emb_dim=d_emb, seq_len=max_len)
|
|
|
|
|
|
|
| 133 |
|
| 134 |
+
self.mlp = nn.Sequential(nn.Linear(d_emb, d_hidden), torch.nn.ReLU(), nn.Linear(d_hidden, hidden_size))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 135 |
|
| 136 |
+
def filter(self, seq_len: int, *args, **kwargs) -> torch.Tensor:
|
| 137 |
return self.mlp(self.pos_emb(seq_len)).transpose(1, 2)
|
| 138 |
|
| 139 |
+
def forward(self, x: torch.Tensor, *args, **kwargs) -> torch.Tensor:
|
| 140 |
"""
|
| 141 |
Args:
|
| 142 |
+
x (torch.Tensor):
|
| 143 |
+
Input of shape [batch_size, seq_len, hidden_size].
|
| 144 |
|
| 145 |
Returns:
|
| 146 |
+
y (torch.Tensor):
|
| 147 |
+
Output of shape [batch_size, seq_len, hidden_size].
|
| 148 |
"""
|
| 149 |
x = x.transpose(1, 2)
|
| 150 |
k = self.filter(x.shape[-1])
|
| 151 |
+
y = fft_conv(u=x, k=k, dropout_mask=None, gelu=False)
|
| 152 |
|
| 153 |
y = y.transpose(1, 2)
|
| 154 |
return y.to(dtype=x.dtype)
|
build/{torch-xpu/modules → torch-cuda/modules/norm}/__init__.py
RENAMED
|
@@ -5,48 +5,46 @@
|
|
| 5 |
# For a list of all contributors, visit:
|
| 6 |
# https://github.com/fla-org/flash-linear-attention/graphs/contributors
|
| 7 |
|
| 8 |
-
from ..modules.
|
| 9 |
-
from ..modules.fused_bitlinear import BitLinear, FusedBitLinear
|
| 10 |
-
from ..modules.fused_cross_entropy import FusedCrossEntropyLoss
|
| 11 |
-
from ..modules.fused_kl_div import FusedKLDivLoss
|
| 12 |
-
from ..modules.fused_linear_cross_entropy import FusedLinearCrossEntropyLoss
|
| 13 |
-
from ..modules.fused_norm_gate import (
|
| 14 |
FusedLayerNormGated,
|
|
|
|
| 15 |
FusedLayerNormSwishGate,
|
| 16 |
FusedLayerNormSwishGateLinear,
|
| 17 |
FusedRMSNormGated,
|
|
|
|
| 18 |
FusedRMSNormSwishGate,
|
| 19 |
FusedRMSNormSwishGateLinear,
|
| 20 |
)
|
| 21 |
-
from ..modules.l2norm import L2Norm
|
| 22 |
-
from ..modules.layernorm import
|
| 23 |
-
|
| 24 |
-
|
| 25 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 26 |
|
| 27 |
__all__ = [
|
| 28 |
-
'BitLinear',
|
| 29 |
-
'FusedBitLinear',
|
| 30 |
-
'FusedCrossEntropyLoss',
|
| 31 |
-
'FusedKLDivLoss',
|
| 32 |
'FusedLayerNormGated',
|
|
|
|
| 33 |
'FusedLayerNormSwishGate',
|
| 34 |
'FusedLayerNormSwishGateLinear',
|
| 35 |
-
'FusedLinearCrossEntropyLoss',
|
| 36 |
'FusedRMSNormGated',
|
|
|
|
| 37 |
'FusedRMSNormSwishGate',
|
| 38 |
'FusedRMSNormSwishGateLinear',
|
| 39 |
-
'GatedMLP',
|
| 40 |
'GroupNorm',
|
| 41 |
'GroupNormLinear',
|
| 42 |
-
'ImplicitLongConvolution',
|
| 43 |
'L2Norm',
|
| 44 |
'LayerNorm',
|
|
|
|
| 45 |
'LayerNormLinear',
|
| 46 |
-
'
|
| 47 |
'RMSNorm',
|
|
|
|
| 48 |
'RMSNormLinear',
|
| 49 |
-
'RotaryEmbedding',
|
| 50 |
-
'ShortConvolution',
|
| 51 |
-
'TokenShift',
|
| 52 |
]
|
|
|
|
|
|
| 5 |
# For a list of all contributors, visit:
|
| 6 |
# https://github.com/fla-org/flash-linear-attention/graphs/contributors
|
| 7 |
|
| 8 |
+
from ...modules.norm.fused_norm_gate import (
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 9 |
FusedLayerNormGated,
|
| 10 |
+
FusedLayerNormGatedLinear,
|
| 11 |
FusedLayerNormSwishGate,
|
| 12 |
FusedLayerNormSwishGateLinear,
|
| 13 |
FusedRMSNormGated,
|
| 14 |
+
FusedRMSNormGatedLinear,
|
| 15 |
FusedRMSNormSwishGate,
|
| 16 |
FusedRMSNormSwishGateLinear,
|
| 17 |
)
|
| 18 |
+
from ...modules.norm.l2norm import L2Norm
|
| 19 |
+
from ...modules.norm.layernorm import (
|
| 20 |
+
GroupNorm,
|
| 21 |
+
GroupNormLinear,
|
| 22 |
+
LayerNorm,
|
| 23 |
+
LayerNormLinear,
|
| 24 |
+
NormParallel,
|
| 25 |
+
RMSNorm,
|
| 26 |
+
RMSNormLinear,
|
| 27 |
+
)
|
| 28 |
+
from ...modules.norm.layernorm_gated import LayerNormGated, RMSNormGated
|
| 29 |
|
| 30 |
__all__ = [
|
|
|
|
|
|
|
|
|
|
|
|
|
| 31 |
'FusedLayerNormGated',
|
| 32 |
+
'FusedLayerNormGatedLinear',
|
| 33 |
'FusedLayerNormSwishGate',
|
| 34 |
'FusedLayerNormSwishGateLinear',
|
|
|
|
| 35 |
'FusedRMSNormGated',
|
| 36 |
+
'FusedRMSNormGatedLinear',
|
| 37 |
'FusedRMSNormSwishGate',
|
| 38 |
'FusedRMSNormSwishGateLinear',
|
|
|
|
| 39 |
'GroupNorm',
|
| 40 |
'GroupNormLinear',
|
|
|
|
| 41 |
'L2Norm',
|
| 42 |
'LayerNorm',
|
| 43 |
+
'LayerNormGated',
|
| 44 |
'LayerNormLinear',
|
| 45 |
+
'NormParallel',
|
| 46 |
'RMSNorm',
|
| 47 |
+
'RMSNormGated',
|
| 48 |
'RMSNormLinear',
|
|
|
|
|
|
|
|
|
|
| 49 |
]
|
| 50 |
+
|
build/{torch-xpu/modules → torch-cuda/modules/norm}/fused_norm_gate.py
RENAMED
|
@@ -15,7 +15,8 @@ import torch.nn.functional as F
|
|
| 15 |
import triton
|
| 16 |
import triton.language as tl
|
| 17 |
|
| 18 |
-
from ..
|
|
|
|
| 19 |
|
| 20 |
|
| 21 |
@triton.heuristics(
|
|
@@ -31,20 +32,20 @@ from ..utils import autotune_cache_kwargs, get_multiprocessor_count, input_guard
|
|
| 31 |
key=["D", "NB", "IS_RMS_NORM", "STORE_RESIDUAL_OUT", "HAS_RESIDUAL", "HAS_WEIGHT"],
|
| 32 |
**autotune_cache_kwargs,
|
| 33 |
)
|
| 34 |
-
@triton.jit
|
| 35 |
def layer_norm_gated_fwd_kernel(
|
| 36 |
-
x,
|
| 37 |
-
g,
|
| 38 |
-
y,
|
| 39 |
-
w,
|
| 40 |
-
b,
|
| 41 |
-
residual,
|
| 42 |
-
residual_out,
|
| 43 |
-
mean,
|
| 44 |
-
rstd,
|
| 45 |
-
eps,
|
| 46 |
-
T,
|
| 47 |
-
D: tl.constexpr,
|
| 48 |
BT: tl.constexpr,
|
| 49 |
BD: tl.constexpr,
|
| 50 |
NB: tl.constexpr,
|
|
@@ -55,23 +56,26 @@ def layer_norm_gated_fwd_kernel(
|
|
| 55 |
HAS_WEIGHT: tl.constexpr,
|
| 56 |
HAS_BIAS: tl.constexpr,
|
| 57 |
):
|
| 58 |
-
i_t = tl.program_id(0)
|
| 59 |
|
|
|
|
| 60 |
o_d = tl.arange(0, BD)
|
| 61 |
m_d = o_d < D
|
|
|
|
|
|
|
| 62 |
|
| 63 |
-
p_x =
|
| 64 |
-
b_x = tl.load(p_x,
|
| 65 |
if HAS_RESIDUAL:
|
| 66 |
-
p_res =
|
| 67 |
-
b_x += tl.load(p_res,
|
| 68 |
if STORE_RESIDUAL_OUT:
|
| 69 |
-
p_res_out =
|
| 70 |
-
tl.store(p_res_out, b_x.to(p_res_out.dtype.element_ty),
|
| 71 |
if not IS_RMS_NORM:
|
| 72 |
b_mean = tl.sum(b_x, axis=1) / D
|
| 73 |
-
p_mean =
|
| 74 |
-
tl.store(p_mean, b_mean.to(p_mean.dtype.element_ty),
|
| 75 |
b_xbar = tl.where(m_d[None, :], b_x - b_mean[:, None], 0.0)
|
| 76 |
b_var = tl.sum(b_xbar * b_xbar, axis=1) / D
|
| 77 |
else:
|
|
@@ -79,8 +83,8 @@ def layer_norm_gated_fwd_kernel(
|
|
| 79 |
b_var = tl.sum(b_xbar * b_xbar, axis=1) / D
|
| 80 |
b_rstd = 1 / tl.sqrt(b_var + eps)
|
| 81 |
|
| 82 |
-
p_rstd =
|
| 83 |
-
tl.store(p_rstd, b_rstd.to(p_rstd.dtype.element_ty),
|
| 84 |
|
| 85 |
if HAS_WEIGHT:
|
| 86 |
b_w = tl.load(w + o_d, mask=m_d).to(tl.float32)
|
|
@@ -92,16 +96,15 @@ def layer_norm_gated_fwd_kernel(
|
|
| 92 |
b_y = b_y + b_b[None, :]
|
| 93 |
|
| 94 |
# swish/sigmoid output gate
|
| 95 |
-
p_g =
|
| 96 |
-
b_g = tl.load(p_g,
|
| 97 |
if ACTIVATION == "swish" or ACTIVATION == "silu":
|
| 98 |
b_y = b_y * b_g * tl.sigmoid(b_g)
|
| 99 |
elif ACTIVATION == "sigmoid":
|
| 100 |
b_y = b_y * tl.sigmoid(b_g)
|
| 101 |
|
| 102 |
-
|
| 103 |
-
|
| 104 |
-
tl.store(p_y, b_y.to(p_y.dtype.element_ty), boundary_check=(0, 1))
|
| 105 |
|
| 106 |
|
| 107 |
@triton.heuristics(
|
|
@@ -118,18 +121,18 @@ def layer_norm_gated_fwd_kernel(
|
|
| 118 |
**autotune_cache_kwargs,
|
| 119 |
)
|
| 120 |
@triton.jit
|
| 121 |
-
def
|
| 122 |
-
x,
|
| 123 |
-
g,
|
| 124 |
-
y,
|
| 125 |
-
w,
|
| 126 |
-
b,
|
| 127 |
-
residual,
|
| 128 |
-
residual_out,
|
| 129 |
-
mean,
|
| 130 |
-
rstd,
|
| 131 |
-
eps,
|
| 132 |
-
D: tl.constexpr,
|
| 133 |
BD: tl.constexpr,
|
| 134 |
ACTIVATION: tl.constexpr,
|
| 135 |
IS_RMS_NORM: tl.constexpr,
|
|
@@ -138,7 +141,7 @@ def layer_norm_gated_fwd_kernel1(
|
|
| 138 |
HAS_WEIGHT: tl.constexpr,
|
| 139 |
HAS_BIAS: tl.constexpr,
|
| 140 |
):
|
| 141 |
-
i_t = tl.program_id(0)
|
| 142 |
x += i_t * D
|
| 143 |
y += i_t * D
|
| 144 |
g += i_t * D
|
|
@@ -181,7 +184,6 @@ def layer_norm_gated_fwd_kernel1(
|
|
| 181 |
elif ACTIVATION == "sigmoid":
|
| 182 |
b_y = b_y * tl.sigmoid(b_g)
|
| 183 |
|
| 184 |
-
# Write output
|
| 185 |
tl.store(y + o_d, b_y, mask=m_d)
|
| 186 |
|
| 187 |
|
|
@@ -198,18 +200,18 @@ def layer_norm_gated_fwd_kernel1(
|
|
| 198 |
key=["D", "NB", "IS_RMS_NORM", "HAS_DRESIDUAL", "HAS_WEIGHT"],
|
| 199 |
**autotune_cache_kwargs,
|
| 200 |
)
|
| 201 |
-
@triton.jit
|
| 202 |
def layer_norm_gated_bwd_kernel(
|
| 203 |
-
x,
|
| 204 |
-
g,
|
| 205 |
-
w,
|
| 206 |
-
b,
|
| 207 |
-
y,
|
| 208 |
-
dy,
|
| 209 |
-
dx,
|
| 210 |
-
dg,
|
| 211 |
-
dw,
|
| 212 |
-
db,
|
| 213 |
dresidual,
|
| 214 |
dresidual_in,
|
| 215 |
mean,
|
|
@@ -228,7 +230,7 @@ def layer_norm_gated_bwd_kernel(
|
|
| 228 |
HAS_BIAS: tl.constexpr,
|
| 229 |
RECOMPUTE_OUTPUT: tl.constexpr,
|
| 230 |
):
|
| 231 |
-
i_s = tl.program_id(0)
|
| 232 |
o_d = tl.arange(0, BD)
|
| 233 |
m_d = o_d < D
|
| 234 |
if HAS_WEIGHT:
|
|
@@ -238,45 +240,45 @@ def layer_norm_gated_bwd_kernel(
|
|
| 238 |
b_b = tl.load(b + o_d, mask=m_d, other=0.0).to(tl.float32)
|
| 239 |
b_db = tl.zeros((BT, BD), dtype=tl.float32)
|
| 240 |
|
| 241 |
-
# the caller guarantees NS = min(SM, T), so every program has at least one token.
|
| 242 |
-
# the last program's range may slightly exceed T (since BS = ceil(T/NS));
|
| 243 |
-
# make_block_ptr uses the true tensor shape (T, D), so boundary_check
|
| 244 |
-
# handles the partial tail tile by zero-padding loads and skipping stores.
|
| 245 |
-
# the m_t mask below further ensures dw/db only accumulate valid rows (< T).
|
| 246 |
for i_t in range(i_s * BS, i_s * BS + BS, BT):
|
| 247 |
-
|
| 248 |
-
|
| 249 |
-
|
| 250 |
-
|
| 251 |
-
|
|
|
|
|
|
|
|
|
|
| 252 |
# [BT, BD]
|
| 253 |
-
b_x = tl.load(p_x,
|
| 254 |
-
b_g = tl.load(p_g,
|
| 255 |
-
b_dy = tl.load(p_dy,
|
| 256 |
|
| 257 |
if not IS_RMS_NORM:
|
| 258 |
-
p_mean =
|
| 259 |
-
b_mean = tl.load(p_mean,
|
| 260 |
-
p_rstd =
|
| 261 |
-
b_rstd = tl.load(p_rstd,
|
| 262 |
-
|
| 263 |
b_xhat = (b_x - b_mean[:, None]) * b_rstd[:, None] if not IS_RMS_NORM else b_x * b_rstd[:, None]
|
| 264 |
b_xhat = tl.where(m_d[None, :], b_xhat, 0.0)
|
| 265 |
|
| 266 |
b_y = b_xhat * b_w[None, :] if HAS_WEIGHT else b_xhat
|
| 267 |
if HAS_BIAS:
|
| 268 |
b_y = b_y + b_b[None, :]
|
| 269 |
-
if RECOMPUTE_OUTPUT:
|
| 270 |
-
p_y = tl.make_block_ptr(y, (T, D), (D, 1), (i_t, 0), (BT, BD), (1, 0))
|
| 271 |
-
tl.store(p_y, b_y.to(p_y.dtype.element_ty), boundary_check=(0, 1))
|
| 272 |
|
| 273 |
b_sigmoid_g = tl.sigmoid(b_g)
|
| 274 |
if ACTIVATION == "swish" or ACTIVATION == "silu":
|
|
|
|
| 275 |
b_dg = b_dy * b_y * (b_sigmoid_g + b_g * b_sigmoid_g * (1 - b_sigmoid_g))
|
| 276 |
-
b_dy = b_dy * b_g * b_sigmoid_g
|
| 277 |
elif ACTIVATION == "sigmoid":
|
|
|
|
| 278 |
b_dg = b_dy * b_y * b_sigmoid_g * (1 - b_sigmoid_g)
|
| 279 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 280 |
b_wdy = b_dy
|
| 281 |
|
| 282 |
if HAS_WEIGHT or HAS_BIAS:
|
|
@@ -296,16 +298,16 @@ def layer_norm_gated_bwd_kernel(
|
|
| 296 |
b_c1 = tl.sum(b_xhat * b_wdy, axis=1) / D
|
| 297 |
b_dx = (b_wdy - b_xhat * b_c1[:, None]) * b_rstd[:, None]
|
| 298 |
if HAS_DRESIDUAL:
|
| 299 |
-
p_dres =
|
| 300 |
-
b_dres = tl.load(p_dres,
|
| 301 |
b_dx += b_dres
|
| 302 |
-
|
| 303 |
if STORE_DRESIDUAL:
|
| 304 |
-
p_dres_in =
|
| 305 |
-
tl.store(p_dres_in, b_dx.to(p_dres_in.dtype.element_ty),
|
| 306 |
|
| 307 |
-
tl.store(p_dx, b_dx.to(p_dx.dtype.element_ty),
|
| 308 |
-
tl.store(p_dg, b_dg.to(p_dg.dtype.element_ty),
|
| 309 |
|
| 310 |
if HAS_WEIGHT:
|
| 311 |
tl.store(dw + i_s * D + o_d, tl.sum(b_dw, axis=0), mask=m_d)
|
|
@@ -326,18 +328,18 @@ def layer_norm_gated_bwd_kernel(
|
|
| 326 |
key=["D", "IS_RMS_NORM", "STORE_DRESIDUAL", "HAS_DRESIDUAL", "HAS_WEIGHT"],
|
| 327 |
**autotune_cache_kwargs,
|
| 328 |
)
|
| 329 |
-
@triton.jit
|
| 330 |
-
def
|
| 331 |
-
x,
|
| 332 |
-
g,
|
| 333 |
-
w,
|
| 334 |
-
b,
|
| 335 |
-
y,
|
| 336 |
-
dy,
|
| 337 |
-
dx,
|
| 338 |
-
dg,
|
| 339 |
-
dw,
|
| 340 |
-
db,
|
| 341 |
dresidual,
|
| 342 |
dresidual_in,
|
| 343 |
mean,
|
|
@@ -354,7 +356,7 @@ def layer_norm_gated_bwd_kernel1(
|
|
| 354 |
HAS_BIAS: tl.constexpr,
|
| 355 |
RECOMPUTE_OUTPUT: tl.constexpr,
|
| 356 |
):
|
| 357 |
-
i_s = tl.program_id(0)
|
| 358 |
o_d = tl.arange(0, BD)
|
| 359 |
mask = o_d < D
|
| 360 |
x += i_s * BS * D
|
|
@@ -376,7 +378,7 @@ def layer_norm_gated_bwd_kernel1(
|
|
| 376 |
b_db = tl.zeros((BD,), dtype=tl.float32)
|
| 377 |
|
| 378 |
for i_t in range(i_s * BS, min(i_s * BS + BS, T)):
|
| 379 |
-
|
| 380 |
b_x = tl.load(x + o_d, mask=mask, other=0).to(tl.float32)
|
| 381 |
b_g = tl.load(g + o_d, mask=mask, other=0).to(tl.float32)
|
| 382 |
b_dy = tl.load(dy + o_d, mask=mask, other=0).to(tl.float32)
|
|
@@ -384,23 +386,25 @@ def layer_norm_gated_bwd_kernel1(
|
|
| 384 |
if not IS_RMS_NORM:
|
| 385 |
b_mean = tl.load(mean + i_t)
|
| 386 |
b_rstd = tl.load(rstd + i_t)
|
| 387 |
-
|
| 388 |
b_xhat = (b_x - b_mean) * b_rstd if not IS_RMS_NORM else b_x * b_rstd
|
| 389 |
b_xhat = tl.where(mask, b_xhat, 0.0)
|
| 390 |
|
| 391 |
b_y = b_xhat * b_w if HAS_WEIGHT else b_xhat
|
| 392 |
if HAS_BIAS:
|
| 393 |
b_y = b_y + b_b
|
| 394 |
-
if RECOMPUTE_OUTPUT:
|
| 395 |
-
tl.store(y + o_d, b_y, mask=mask)
|
| 396 |
|
| 397 |
b_sigmoid_g = tl.sigmoid(b_g)
|
| 398 |
if ACTIVATION == "swish" or ACTIVATION == "silu":
|
|
|
|
| 399 |
b_dg = b_dy * b_y * (b_sigmoid_g + b_g * b_sigmoid_g * (1 - b_sigmoid_g))
|
| 400 |
-
b_dy = b_dy * b_g * b_sigmoid_g
|
| 401 |
elif ACTIVATION == "sigmoid":
|
|
|
|
| 402 |
b_dg = b_dy * b_y * b_sigmoid_g * (1 - b_sigmoid_g)
|
| 403 |
-
|
|
|
|
|
|
|
|
|
|
| 404 |
b_wdy = b_dy
|
| 405 |
if HAS_WEIGHT:
|
| 406 |
b_wdy = b_dy * b_w
|
|
@@ -417,7 +421,7 @@ def layer_norm_gated_bwd_kernel1(
|
|
| 417 |
if HAS_DRESIDUAL:
|
| 418 |
b_dres = tl.load(dresidual + o_d, mask=mask, other=0).to(tl.float32)
|
| 419 |
b_dx += b_dres
|
| 420 |
-
|
| 421 |
if STORE_DRESIDUAL:
|
| 422 |
tl.store(dresidual_in + o_d, b_dx, mask=mask)
|
| 423 |
tl.store(dx + o_d, b_dx, mask=mask)
|
|
@@ -440,6 +444,8 @@ def layer_norm_gated_bwd_kernel1(
|
|
| 440 |
tl.store(db + i_s * D + o_d, b_db, mask=mask)
|
| 441 |
|
| 442 |
|
|
|
|
|
|
|
| 443 |
def layer_norm_gated_fwd(
|
| 444 |
x: torch.Tensor,
|
| 445 |
g: torch.Tensor,
|
|
@@ -447,9 +453,9 @@ def layer_norm_gated_fwd(
|
|
| 447 |
bias: torch.Tensor,
|
| 448 |
activation: str = "swish",
|
| 449 |
eps: float = 1e-5,
|
| 450 |
-
residual: torch.Tensor = None,
|
| 451 |
-
out_dtype: torch.dtype = None,
|
| 452 |
-
residual_dtype: torch.dtype = None,
|
| 453 |
is_rms_norm: bool = False,
|
| 454 |
):
|
| 455 |
if residual is not None:
|
|
@@ -461,7 +467,7 @@ def layer_norm_gated_fwd(
|
|
| 461 |
assert weight.shape == (D,)
|
| 462 |
if bias is not None:
|
| 463 |
assert bias.shape == (D,)
|
| 464 |
-
|
| 465 |
y = torch.empty_like(x, dtype=x.dtype if out_dtype is None else out_dtype)
|
| 466 |
if residual is not None or (residual_dtype is not None and residual_dtype != x.dtype):
|
| 467 |
residual_out = torch.empty(T, D, device=x.device, dtype=residual_dtype)
|
|
@@ -469,17 +475,13 @@ def layer_norm_gated_fwd(
|
|
| 469 |
residual_out = None
|
| 470 |
mean = torch.empty((T,), dtype=torch.float, device=x.device) if not is_rms_norm else None
|
| 471 |
rstd = torch.empty((T,), dtype=torch.float, device=x.device)
|
| 472 |
-
|
| 473 |
MAX_FUSED_SIZE = 65536 // x.element_size()
|
| 474 |
BD = min(MAX_FUSED_SIZE, triton.next_power_of_2(D))
|
| 475 |
if D > BD:
|
| 476 |
raise RuntimeError("This layer norm doesn't support feature dim >= 64KB.")
|
| 477 |
-
# heuristics for number of warps
|
| 478 |
-
|
| 479 |
if D <= 512:
|
| 480 |
-
#
|
| 481 |
-
# of T before recompiling the kernel.
|
| 482 |
-
# NB = triton.cdiv(T, 2048)
|
| 483 |
NB = triton.cdiv(T, 2048 * 32)
|
| 484 |
|
| 485 |
def grid(meta):
|
|
@@ -504,7 +506,7 @@ def layer_norm_gated_fwd(
|
|
| 504 |
IS_RMS_NORM=is_rms_norm,
|
| 505 |
)
|
| 506 |
else:
|
| 507 |
-
|
| 508 |
x=x,
|
| 509 |
g=g,
|
| 510 |
y=y,
|
|
@@ -524,6 +526,8 @@ def layer_norm_gated_fwd(
|
|
| 524 |
return y, mean, rstd, residual_out if residual_out is not None else x
|
| 525 |
|
| 526 |
|
|
|
|
|
|
|
| 527 |
def layer_norm_gated_bwd(
|
| 528 |
dy: torch.Tensor,
|
| 529 |
x: torch.Tensor,
|
|
@@ -532,12 +536,12 @@ def layer_norm_gated_bwd(
|
|
| 532 |
bias: torch.Tensor,
|
| 533 |
activation: str = "swish",
|
| 534 |
eps: float = 1e-5,
|
| 535 |
-
mean: torch.Tensor = None,
|
| 536 |
-
rstd: torch.Tensor = None,
|
| 537 |
-
dresidual: torch.Tensor = None,
|
| 538 |
has_residual: bool = False,
|
| 539 |
is_rms_norm: bool = False,
|
| 540 |
-
x_dtype: torch.dtype = None,
|
| 541 |
recompute_output: bool = False,
|
| 542 |
):
|
| 543 |
T, D = x.shape
|
|
@@ -548,20 +552,17 @@ def layer_norm_gated_bwd(
|
|
| 548 |
assert weight.shape == (D,)
|
| 549 |
if bias is not None:
|
| 550 |
assert bias.shape == (D,)
|
| 551 |
-
|
| 552 |
dx = torch.empty_like(x) if x_dtype is None else torch.empty(T, D, dtype=x_dtype, device=x.device)
|
| 553 |
dg = torch.empty_like(g) if x_dtype is None else torch.empty(T, D, dtype=x_dtype, device=x.device)
|
| 554 |
dresidual_in = torch.empty_like(x) if has_residual and dx.dtype != x.dtype else None
|
| 555 |
y = torch.empty(T, D, dtype=dy.dtype, device=dy.device) if recompute_output else None
|
| 556 |
|
| 557 |
-
# Less than 64KB per feature: enqueue fused kernel
|
| 558 |
MAX_FUSED_SIZE = 65536 // x.element_size()
|
| 559 |
BD = min(MAX_FUSED_SIZE, triton.next_power_of_2(D))
|
| 560 |
if D > BD:
|
| 561 |
raise RuntimeError("This layer norm doesn't support feature dim >= 64KB.")
|
| 562 |
-
# cap program count
|
| 563 |
-
# without this, high-SM GPUs (e.g. B200, 160 SMs) with small T would
|
| 564 |
-
# launch idle programs whose make_block_ptr offsets exceed the tensor shape.
|
| 565 |
NS = min(get_multiprocessor_count(x.device.index), T)
|
| 566 |
BS = math.ceil(T / NS)
|
| 567 |
|
|
@@ -570,9 +571,7 @@ def layer_norm_gated_bwd(
|
|
| 570 |
grid = (NS,)
|
| 571 |
|
| 572 |
if D <= 512:
|
| 573 |
-
#
|
| 574 |
-
# of T before recompiling the kernel.
|
| 575 |
-
# NB = triton.cdiv(T, 2048)
|
| 576 |
NB = triton.cdiv(T, 2048 * 32)
|
| 577 |
|
| 578 |
layer_norm_gated_bwd_kernel[grid](
|
|
@@ -591,8 +590,8 @@ def layer_norm_gated_bwd(
|
|
| 591 |
mean=mean,
|
| 592 |
rstd=rstd,
|
| 593 |
T=T,
|
| 594 |
-
D=D,
|
| 595 |
BS=BS,
|
|
|
|
| 596 |
BD=BD,
|
| 597 |
NB=NB,
|
| 598 |
ACTIVATION=activation,
|
|
@@ -600,7 +599,7 @@ def layer_norm_gated_bwd(
|
|
| 600 |
STORE_DRESIDUAL=dresidual_in is not None,
|
| 601 |
)
|
| 602 |
else:
|
| 603 |
-
|
| 604 |
x=x,
|
| 605 |
g=g,
|
| 606 |
w=weight,
|
|
@@ -616,8 +615,8 @@ def layer_norm_gated_bwd(
|
|
| 616 |
mean=mean,
|
| 617 |
rstd=rstd,
|
| 618 |
T=T,
|
| 619 |
-
D=D,
|
| 620 |
BS=BS,
|
|
|
|
| 621 |
BD=BD,
|
| 622 |
ACTIVATION=activation,
|
| 623 |
IS_RMS_NORM=is_rms_norm,
|
|
@@ -625,7 +624,7 @@ def layer_norm_gated_bwd(
|
|
| 625 |
)
|
| 626 |
dw = dw.sum(0).to(weight.dtype) if weight is not None else None
|
| 627 |
db = db.sum(0).to(bias.dtype) if bias is not None else None
|
| 628 |
-
#
|
| 629 |
if has_residual and dx.dtype == x.dtype:
|
| 630 |
dresidual_in = dx
|
| 631 |
return (dx, dg, dw, db, dresidual_in) if not recompute_output else (dx, dg, dw, db, dresidual_in, y)
|
|
@@ -649,7 +648,7 @@ class LayerNormGatedFunction(torch.autograd.Function):
|
|
| 649 |
):
|
| 650 |
x_shape_og = x.shape
|
| 651 |
g_shape_og = g.shape
|
| 652 |
-
|
| 653 |
x = x.reshape(-1, x.shape[-1])
|
| 654 |
g = g.reshape(-1, g.shape[-1])
|
| 655 |
if residual is not None:
|
|
@@ -739,7 +738,7 @@ class LayerNormGatedLinearFunction(torch.autograd.Function):
|
|
| 739 |
):
|
| 740 |
x_shape_og = x.shape
|
| 741 |
g_shape_og = g.shape
|
| 742 |
-
|
| 743 |
x = x.reshape(-1, x.shape[-1])
|
| 744 |
g = g.reshape(-1, g.shape[-1])
|
| 745 |
if residual is not None:
|
|
@@ -761,7 +760,7 @@ class LayerNormGatedLinearFunction(torch.autograd.Function):
|
|
| 761 |
linear_weight = linear_weight.to(dtype)
|
| 762 |
linear_bias = linear_bias.to(dtype) if linear_bias is not None else None
|
| 763 |
out = F.linear(y.to(linear_weight.dtype), linear_weight, linear_bias)
|
| 764 |
-
#
|
| 765 |
ctx.save_for_backward(residual_out, g, norm_weight, norm_bias, linear_weight, mean, rstd)
|
| 766 |
ctx.x_shape_og = x_shape_og
|
| 767 |
ctx.g_shape_og = g_shape_og
|
|
@@ -829,18 +828,7 @@ def layer_norm_gated(
|
|
| 829 |
residual_in_fp32: bool = False,
|
| 830 |
eps: float = 1e-6,
|
| 831 |
):
|
| 832 |
-
return LayerNormGatedFunction.apply(
|
| 833 |
-
x,
|
| 834 |
-
g,
|
| 835 |
-
weight,
|
| 836 |
-
bias,
|
| 837 |
-
activation,
|
| 838 |
-
residual,
|
| 839 |
-
eps,
|
| 840 |
-
prenorm,
|
| 841 |
-
residual_in_fp32,
|
| 842 |
-
False,
|
| 843 |
-
)
|
| 844 |
|
| 845 |
|
| 846 |
def rms_norm_gated(
|
|
@@ -854,18 +842,7 @@ def rms_norm_gated(
|
|
| 854 |
residual_in_fp32: bool = False,
|
| 855 |
eps: float = 1e-6,
|
| 856 |
):
|
| 857 |
-
return LayerNormGatedFunction.apply(
|
| 858 |
-
x,
|
| 859 |
-
g,
|
| 860 |
-
weight,
|
| 861 |
-
bias,
|
| 862 |
-
activation,
|
| 863 |
-
residual,
|
| 864 |
-
eps,
|
| 865 |
-
prenorm,
|
| 866 |
-
residual_in_fp32,
|
| 867 |
-
True,
|
| 868 |
-
)
|
| 869 |
|
| 870 |
|
| 871 |
def layer_norm_swish_gate_linear(
|
|
@@ -932,7 +909,7 @@ class FusedLayerNormGated(nn.Module):
|
|
| 932 |
eps: float = 1e-5,
|
| 933 |
device: torch.device | None = None,
|
| 934 |
dtype: torch.dtype | None = None,
|
| 935 |
-
) ->
|
| 936 |
factory_kwargs = {"device": device, "dtype": dtype}
|
| 937 |
super().__init__()
|
| 938 |
|
|
@@ -975,17 +952,17 @@ class FusedLayerNormGated(nn.Module):
|
|
| 975 |
residual: torch.Tensor | None = None,
|
| 976 |
prenorm: bool = False,
|
| 977 |
residual_in_fp32: bool = False,
|
| 978 |
-
) -> torch.Tensor:
|
| 979 |
return layer_norm_gated(
|
| 980 |
-
x,
|
| 981 |
-
g,
|
| 982 |
-
self.weight,
|
| 983 |
-
self.bias,
|
| 984 |
-
self.activation,
|
| 985 |
residual=residual,
|
| 986 |
-
eps=self.eps,
|
| 987 |
prenorm=prenorm,
|
| 988 |
residual_in_fp32=residual_in_fp32,
|
|
|
|
| 989 |
)
|
| 990 |
|
| 991 |
|
|
@@ -998,7 +975,7 @@ class FusedRMSNormGated(nn.Module):
|
|
| 998 |
activation: str = "swish",
|
| 999 |
device: torch.device | None = None,
|
| 1000 |
dtype: torch.dtype | None = None,
|
| 1001 |
-
) ->
|
| 1002 |
factory_kwargs = {"device": device, "dtype": dtype}
|
| 1003 |
super().__init__()
|
| 1004 |
|
|
@@ -1038,17 +1015,17 @@ class FusedRMSNormGated(nn.Module):
|
|
| 1038 |
residual: torch.Tensor | None = None,
|
| 1039 |
prenorm: bool = False,
|
| 1040 |
residual_in_fp32: bool = False,
|
| 1041 |
-
) -> torch.Tensor:
|
| 1042 |
return rms_norm_gated(
|
| 1043 |
-
x,
|
| 1044 |
-
g,
|
| 1045 |
-
self.weight,
|
| 1046 |
-
self.bias,
|
| 1047 |
-
self.activation,
|
| 1048 |
residual=residual,
|
| 1049 |
-
eps=self.eps,
|
| 1050 |
prenorm=prenorm,
|
| 1051 |
residual_in_fp32=residual_in_fp32,
|
|
|
|
| 1052 |
)
|
| 1053 |
|
| 1054 |
|
|
@@ -1061,7 +1038,7 @@ class FusedLayerNormSwishGate(FusedLayerNormGated):
|
|
| 1061 |
eps: float = 1e-5,
|
| 1062 |
device: torch.device | None = None,
|
| 1063 |
dtype: torch.dtype | None = None,
|
| 1064 |
-
) ->
|
| 1065 |
super().__init__(
|
| 1066 |
hidden_size=hidden_size,
|
| 1067 |
elementwise_affine=elementwise_affine,
|
|
@@ -1080,14 +1057,8 @@ class FusedRMSNormSwishGate(FusedRMSNormGated):
|
|
| 1080 |
eps: float = 1e-5,
|
| 1081 |
device: torch.device | None = None,
|
| 1082 |
dtype: torch.dtype | None = None,
|
| 1083 |
-
) ->
|
| 1084 |
-
super().__init__(
|
| 1085 |
-
hidden_size=hidden_size,
|
| 1086 |
-
elementwise_affine=elementwise_affine,
|
| 1087 |
-
eps=eps,
|
| 1088 |
-
device=device,
|
| 1089 |
-
dtype=dtype,
|
| 1090 |
-
)
|
| 1091 |
|
| 1092 |
|
| 1093 |
class FusedLayerNormGatedLinear(nn.Module):
|
|
@@ -1098,7 +1069,7 @@ class FusedLayerNormGatedLinear(nn.Module):
|
|
| 1098 |
eps: float = 1e-5,
|
| 1099 |
device: torch.device | None = None,
|
| 1100 |
dtype: torch.dtype | None = None,
|
| 1101 |
-
) ->
|
| 1102 |
factory_kwargs = {"device": device, "dtype": dtype}
|
| 1103 |
super().__init__()
|
| 1104 |
|
|
@@ -1135,18 +1106,18 @@ class FusedLayerNormGatedLinear(nn.Module):
|
|
| 1135 |
residual: torch.Tensor | None = None,
|
| 1136 |
prenorm: bool = False,
|
| 1137 |
residual_in_fp32: bool = False,
|
| 1138 |
-
) -> torch.Tensor:
|
| 1139 |
return layer_norm_swish_gate_linear(
|
| 1140 |
-
x,
|
| 1141 |
-
g,
|
| 1142 |
-
self.weight,
|
| 1143 |
-
self.bias,
|
| 1144 |
-
weight,
|
| 1145 |
-
bias,
|
| 1146 |
residual=residual,
|
| 1147 |
-
eps=self.eps,
|
| 1148 |
prenorm=prenorm,
|
| 1149 |
residual_in_fp32=residual_in_fp32,
|
|
|
|
| 1150 |
)
|
| 1151 |
|
| 1152 |
|
|
@@ -1158,25 +1129,19 @@ class FusedLayerNormSwishGateLinear(FusedLayerNormGatedLinear):
|
|
| 1158 |
eps: float = 1e-5,
|
| 1159 |
device: torch.device | None = None,
|
| 1160 |
dtype: torch.dtype | None = None,
|
| 1161 |
-
) ->
|
| 1162 |
-
super().__init__(
|
| 1163 |
-
hidden_size=hidden_size,
|
| 1164 |
-
elementwise_affine=elementwise_affine,
|
| 1165 |
-
eps=eps,
|
| 1166 |
-
device=device,
|
| 1167 |
-
dtype=dtype,
|
| 1168 |
-
)
|
| 1169 |
|
| 1170 |
|
| 1171 |
class FusedRMSNormGatedLinear(nn.Module):
|
| 1172 |
def __init__(
|
| 1173 |
self,
|
| 1174 |
-
hidden_size,
|
| 1175 |
elementwise_affine: bool = True,
|
| 1176 |
eps: float = 1e-5,
|
| 1177 |
device: torch.device | None = None,
|
| 1178 |
dtype: torch.dtype | None = None,
|
| 1179 |
-
) ->
|
| 1180 |
factory_kwargs = {"device": device, "dtype": dtype}
|
| 1181 |
super().__init__()
|
| 1182 |
|
|
@@ -1212,18 +1177,18 @@ class FusedRMSNormGatedLinear(nn.Module):
|
|
| 1212 |
residual: torch.Tensor | None = None,
|
| 1213 |
prenorm: bool = False,
|
| 1214 |
residual_in_fp32: bool = False,
|
| 1215 |
-
) -> torch.Tensor:
|
| 1216 |
return rms_norm_swish_gate_linear(
|
| 1217 |
-
x,
|
| 1218 |
-
g,
|
| 1219 |
-
self.weight,
|
| 1220 |
-
self.bias,
|
| 1221 |
-
weight,
|
| 1222 |
-
bias,
|
| 1223 |
residual=residual,
|
| 1224 |
-
eps=self.eps,
|
| 1225 |
prenorm=prenorm,
|
| 1226 |
residual_in_fp32=residual_in_fp32,
|
|
|
|
| 1227 |
)
|
| 1228 |
|
| 1229 |
|
|
@@ -1235,11 +1200,23 @@ class FusedRMSNormSwishGateLinear(FusedRMSNormGatedLinear):
|
|
| 1235 |
eps: float = 1e-5,
|
| 1236 |
device: torch.device | None = None,
|
| 1237 |
dtype: torch.dtype | None = None,
|
| 1238 |
-
) ->
|
| 1239 |
-
super().__init__(
|
| 1240 |
-
|
| 1241 |
-
|
| 1242 |
-
|
| 1243 |
-
|
| 1244 |
-
|
| 1245 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 15 |
import triton
|
| 16 |
import triton.language as tl
|
| 17 |
|
| 18 |
+
from ...backends import dispatch
|
| 19 |
+
from ...utils import autotune_cache_kwargs, get_multiprocessor_count, input_guard
|
| 20 |
|
| 21 |
|
| 22 |
@triton.heuristics(
|
|
|
|
| 32 |
key=["D", "NB", "IS_RMS_NORM", "STORE_RESIDUAL_OUT", "HAS_RESIDUAL", "HAS_WEIGHT"],
|
| 33 |
**autotune_cache_kwargs,
|
| 34 |
)
|
| 35 |
+
@triton.jit(do_not_specialize=['T'])
|
| 36 |
def layer_norm_gated_fwd_kernel(
|
| 37 |
+
x,
|
| 38 |
+
g,
|
| 39 |
+
y,
|
| 40 |
+
w,
|
| 41 |
+
b,
|
| 42 |
+
residual,
|
| 43 |
+
residual_out,
|
| 44 |
+
mean,
|
| 45 |
+
rstd,
|
| 46 |
+
eps,
|
| 47 |
+
T,
|
| 48 |
+
D: tl.constexpr,
|
| 49 |
BT: tl.constexpr,
|
| 50 |
BD: tl.constexpr,
|
| 51 |
NB: tl.constexpr,
|
|
|
|
| 56 |
HAS_WEIGHT: tl.constexpr,
|
| 57 |
HAS_BIAS: tl.constexpr,
|
| 58 |
):
|
| 59 |
+
i_t = tl.program_id(0).to(tl.int64)
|
| 60 |
|
| 61 |
+
o_t = i_t * BT + tl.arange(0, BT)
|
| 62 |
o_d = tl.arange(0, BD)
|
| 63 |
m_d = o_d < D
|
| 64 |
+
m_t = o_t < T
|
| 65 |
+
m_x = m_t[:, None] & m_d[None, :]
|
| 66 |
|
| 67 |
+
p_x = x + o_t[:, None] * D + o_d[None, :]
|
| 68 |
+
b_x = tl.load(p_x, mask=m_x, other=0.0).to(tl.float32)
|
| 69 |
if HAS_RESIDUAL:
|
| 70 |
+
p_res = residual + o_t[:, None] * D + o_d[None, :]
|
| 71 |
+
b_x += tl.load(p_res, mask=m_x, other=0.0).to(tl.float32)
|
| 72 |
if STORE_RESIDUAL_OUT:
|
| 73 |
+
p_res_out = residual_out + o_t[:, None] * D + o_d[None, :]
|
| 74 |
+
tl.store(p_res_out, b_x.to(p_res_out.dtype.element_ty), mask=m_x)
|
| 75 |
if not IS_RMS_NORM:
|
| 76 |
b_mean = tl.sum(b_x, axis=1) / D
|
| 77 |
+
p_mean = mean + o_t
|
| 78 |
+
tl.store(p_mean, b_mean.to(p_mean.dtype.element_ty), mask=m_t)
|
| 79 |
b_xbar = tl.where(m_d[None, :], b_x - b_mean[:, None], 0.0)
|
| 80 |
b_var = tl.sum(b_xbar * b_xbar, axis=1) / D
|
| 81 |
else:
|
|
|
|
| 83 |
b_var = tl.sum(b_xbar * b_xbar, axis=1) / D
|
| 84 |
b_rstd = 1 / tl.sqrt(b_var + eps)
|
| 85 |
|
| 86 |
+
p_rstd = rstd + o_t
|
| 87 |
+
tl.store(p_rstd, b_rstd.to(p_rstd.dtype.element_ty), mask=m_t)
|
| 88 |
|
| 89 |
if HAS_WEIGHT:
|
| 90 |
b_w = tl.load(w + o_d, mask=m_d).to(tl.float32)
|
|
|
|
| 96 |
b_y = b_y + b_b[None, :]
|
| 97 |
|
| 98 |
# swish/sigmoid output gate
|
| 99 |
+
p_g = g + o_t[:, None] * D + o_d[None, :]
|
| 100 |
+
b_g = tl.load(p_g, mask=m_x, other=0.0).to(tl.float32)
|
| 101 |
if ACTIVATION == "swish" or ACTIVATION == "silu":
|
| 102 |
b_y = b_y * b_g * tl.sigmoid(b_g)
|
| 103 |
elif ACTIVATION == "sigmoid":
|
| 104 |
b_y = b_y * tl.sigmoid(b_g)
|
| 105 |
|
| 106 |
+
p_y = y + o_t[:, None] * D + o_d[None, :]
|
| 107 |
+
tl.store(p_y, b_y.to(p_y.dtype.element_ty), mask=m_x)
|
|
|
|
| 108 |
|
| 109 |
|
| 110 |
@triton.heuristics(
|
|
|
|
| 121 |
**autotune_cache_kwargs,
|
| 122 |
)
|
| 123 |
@triton.jit
|
| 124 |
+
def layer_norm_gated_fwd_kernel_row(
|
| 125 |
+
x,
|
| 126 |
+
g,
|
| 127 |
+
y,
|
| 128 |
+
w,
|
| 129 |
+
b,
|
| 130 |
+
residual,
|
| 131 |
+
residual_out,
|
| 132 |
+
mean,
|
| 133 |
+
rstd,
|
| 134 |
+
eps,
|
| 135 |
+
D: tl.constexpr,
|
| 136 |
BD: tl.constexpr,
|
| 137 |
ACTIVATION: tl.constexpr,
|
| 138 |
IS_RMS_NORM: tl.constexpr,
|
|
|
|
| 141 |
HAS_WEIGHT: tl.constexpr,
|
| 142 |
HAS_BIAS: tl.constexpr,
|
| 143 |
):
|
| 144 |
+
i_t = tl.program_id(0).to(tl.int64)
|
| 145 |
x += i_t * D
|
| 146 |
y += i_t * D
|
| 147 |
g += i_t * D
|
|
|
|
| 184 |
elif ACTIVATION == "sigmoid":
|
| 185 |
b_y = b_y * tl.sigmoid(b_g)
|
| 186 |
|
|
|
|
| 187 |
tl.store(y + o_d, b_y, mask=m_d)
|
| 188 |
|
| 189 |
|
|
|
|
| 200 |
key=["D", "NB", "IS_RMS_NORM", "HAS_DRESIDUAL", "HAS_WEIGHT"],
|
| 201 |
**autotune_cache_kwargs,
|
| 202 |
)
|
| 203 |
+
@triton.jit(do_not_specialize=['T'])
|
| 204 |
def layer_norm_gated_bwd_kernel(
|
| 205 |
+
x,
|
| 206 |
+
g,
|
| 207 |
+
w,
|
| 208 |
+
b,
|
| 209 |
+
y,
|
| 210 |
+
dy,
|
| 211 |
+
dx,
|
| 212 |
+
dg,
|
| 213 |
+
dw,
|
| 214 |
+
db,
|
| 215 |
dresidual,
|
| 216 |
dresidual_in,
|
| 217 |
mean,
|
|
|
|
| 230 |
HAS_BIAS: tl.constexpr,
|
| 231 |
RECOMPUTE_OUTPUT: tl.constexpr,
|
| 232 |
):
|
| 233 |
+
i_s = tl.program_id(0).to(tl.int64)
|
| 234 |
o_d = tl.arange(0, BD)
|
| 235 |
m_d = o_d < D
|
| 236 |
if HAS_WEIGHT:
|
|
|
|
| 240 |
b_b = tl.load(b + o_d, mask=m_d, other=0.0).to(tl.float32)
|
| 241 |
b_db = tl.zeros((BT, BD), dtype=tl.float32)
|
| 242 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 243 |
for i_t in range(i_s * BS, i_s * BS + BS, BT):
|
| 244 |
+
o_t = (i_t + tl.arange(0, BT)).to(tl.int64)
|
| 245 |
+
m_t = o_t < T
|
| 246 |
+
m_x = m_t[:, None] & m_d[None, :]
|
| 247 |
+
p_x = x + o_t[:, None] * D + o_d[None, :]
|
| 248 |
+
p_g = g + o_t[:, None] * D + o_d[None, :]
|
| 249 |
+
p_dy = dy + o_t[:, None] * D + o_d[None, :]
|
| 250 |
+
p_dx = dx + o_t[:, None] * D + o_d[None, :]
|
| 251 |
+
p_dg = dg + o_t[:, None] * D + o_d[None, :]
|
| 252 |
# [BT, BD]
|
| 253 |
+
b_x = tl.load(p_x, mask=m_x, other=0.0).to(tl.float32)
|
| 254 |
+
b_g = tl.load(p_g, mask=m_x, other=0.0).to(tl.float32)
|
| 255 |
+
b_dy = tl.load(p_dy, mask=m_x, other=0.0).to(tl.float32)
|
| 256 |
|
| 257 |
if not IS_RMS_NORM:
|
| 258 |
+
p_mean = mean + o_t
|
| 259 |
+
b_mean = tl.load(p_mean, mask=m_t, other=0.0)
|
| 260 |
+
p_rstd = rstd + o_t
|
| 261 |
+
b_rstd = tl.load(p_rstd, mask=m_t, other=0.0)
|
| 262 |
+
|
| 263 |
b_xhat = (b_x - b_mean[:, None]) * b_rstd[:, None] if not IS_RMS_NORM else b_x * b_rstd[:, None]
|
| 264 |
b_xhat = tl.where(m_d[None, :], b_xhat, 0.0)
|
| 265 |
|
| 266 |
b_y = b_xhat * b_w[None, :] if HAS_WEIGHT else b_xhat
|
| 267 |
if HAS_BIAS:
|
| 268 |
b_y = b_y + b_b[None, :]
|
|
|
|
|
|
|
|
|
|
| 269 |
|
| 270 |
b_sigmoid_g = tl.sigmoid(b_g)
|
| 271 |
if ACTIVATION == "swish" or ACTIVATION == "silu":
|
| 272 |
+
b_gate = b_g * b_sigmoid_g
|
| 273 |
b_dg = b_dy * b_y * (b_sigmoid_g + b_g * b_sigmoid_g * (1 - b_sigmoid_g))
|
|
|
|
| 274 |
elif ACTIVATION == "sigmoid":
|
| 275 |
+
b_gate = b_sigmoid_g
|
| 276 |
b_dg = b_dy * b_y * b_sigmoid_g * (1 - b_sigmoid_g)
|
| 277 |
+
# b_dg needs pre-gate b_y; the recomputed output must include the gate to match the caller's linear input.
|
| 278 |
+
if RECOMPUTE_OUTPUT:
|
| 279 |
+
p_y = y + o_t[:, None] * D + o_d[None, :]
|
| 280 |
+
tl.store(p_y, (b_y * b_gate).to(p_y.dtype.element_ty), mask=m_x)
|
| 281 |
+
b_dy = b_dy * b_gate
|
| 282 |
b_wdy = b_dy
|
| 283 |
|
| 284 |
if HAS_WEIGHT or HAS_BIAS:
|
|
|
|
| 298 |
b_c1 = tl.sum(b_xhat * b_wdy, axis=1) / D
|
| 299 |
b_dx = (b_wdy - b_xhat * b_c1[:, None]) * b_rstd[:, None]
|
| 300 |
if HAS_DRESIDUAL:
|
| 301 |
+
p_dres = dresidual + o_t[:, None] * D + o_d[None, :]
|
| 302 |
+
b_dres = tl.load(p_dres, mask=m_x, other=0.0).to(tl.float32)
|
| 303 |
b_dx += b_dres
|
| 304 |
+
|
| 305 |
if STORE_DRESIDUAL:
|
| 306 |
+
p_dres_in = dresidual_in + o_t[:, None] * D + o_d[None, :]
|
| 307 |
+
tl.store(p_dres_in, b_dx.to(p_dres_in.dtype.element_ty), mask=m_x)
|
| 308 |
|
| 309 |
+
tl.store(p_dx, b_dx.to(p_dx.dtype.element_ty), mask=m_x)
|
| 310 |
+
tl.store(p_dg, b_dg.to(p_dg.dtype.element_ty), mask=m_x)
|
| 311 |
|
| 312 |
if HAS_WEIGHT:
|
| 313 |
tl.store(dw + i_s * D + o_d, tl.sum(b_dw, axis=0), mask=m_d)
|
|
|
|
| 328 |
key=["D", "IS_RMS_NORM", "STORE_DRESIDUAL", "HAS_DRESIDUAL", "HAS_WEIGHT"],
|
| 329 |
**autotune_cache_kwargs,
|
| 330 |
)
|
| 331 |
+
@triton.jit(do_not_specialize=['T'])
|
| 332 |
+
def layer_norm_gated_bwd_kernel_row(
|
| 333 |
+
x,
|
| 334 |
+
g,
|
| 335 |
+
w,
|
| 336 |
+
b,
|
| 337 |
+
y,
|
| 338 |
+
dy,
|
| 339 |
+
dx,
|
| 340 |
+
dg,
|
| 341 |
+
dw,
|
| 342 |
+
db,
|
| 343 |
dresidual,
|
| 344 |
dresidual_in,
|
| 345 |
mean,
|
|
|
|
| 356 |
HAS_BIAS: tl.constexpr,
|
| 357 |
RECOMPUTE_OUTPUT: tl.constexpr,
|
| 358 |
):
|
| 359 |
+
i_s = tl.program_id(0).to(tl.int64)
|
| 360 |
o_d = tl.arange(0, BD)
|
| 361 |
mask = o_d < D
|
| 362 |
x += i_s * BS * D
|
|
|
|
| 378 |
b_db = tl.zeros((BD,), dtype=tl.float32)
|
| 379 |
|
| 380 |
for i_t in range(i_s * BS, min(i_s * BS + BS, T)):
|
| 381 |
+
|
| 382 |
b_x = tl.load(x + o_d, mask=mask, other=0).to(tl.float32)
|
| 383 |
b_g = tl.load(g + o_d, mask=mask, other=0).to(tl.float32)
|
| 384 |
b_dy = tl.load(dy + o_d, mask=mask, other=0).to(tl.float32)
|
|
|
|
| 386 |
if not IS_RMS_NORM:
|
| 387 |
b_mean = tl.load(mean + i_t)
|
| 388 |
b_rstd = tl.load(rstd + i_t)
|
| 389 |
+
|
| 390 |
b_xhat = (b_x - b_mean) * b_rstd if not IS_RMS_NORM else b_x * b_rstd
|
| 391 |
b_xhat = tl.where(mask, b_xhat, 0.0)
|
| 392 |
|
| 393 |
b_y = b_xhat * b_w if HAS_WEIGHT else b_xhat
|
| 394 |
if HAS_BIAS:
|
| 395 |
b_y = b_y + b_b
|
|
|
|
|
|
|
| 396 |
|
| 397 |
b_sigmoid_g = tl.sigmoid(b_g)
|
| 398 |
if ACTIVATION == "swish" or ACTIVATION == "silu":
|
| 399 |
+
b_gate = b_g * b_sigmoid_g
|
| 400 |
b_dg = b_dy * b_y * (b_sigmoid_g + b_g * b_sigmoid_g * (1 - b_sigmoid_g))
|
|
|
|
| 401 |
elif ACTIVATION == "sigmoid":
|
| 402 |
+
b_gate = b_sigmoid_g
|
| 403 |
b_dg = b_dy * b_y * b_sigmoid_g * (1 - b_sigmoid_g)
|
| 404 |
+
# b_dg needs pre-gate b_y; the recomputed output must include the gate to match the caller's linear input.
|
| 405 |
+
if RECOMPUTE_OUTPUT:
|
| 406 |
+
tl.store(y + o_d, b_y * b_gate, mask=mask)
|
| 407 |
+
b_dy = b_dy * b_gate
|
| 408 |
b_wdy = b_dy
|
| 409 |
if HAS_WEIGHT:
|
| 410 |
b_wdy = b_dy * b_w
|
|
|
|
| 421 |
if HAS_DRESIDUAL:
|
| 422 |
b_dres = tl.load(dresidual + o_d, mask=mask, other=0).to(tl.float32)
|
| 423 |
b_dx += b_dres
|
| 424 |
+
|
| 425 |
if STORE_DRESIDUAL:
|
| 426 |
tl.store(dresidual_in + o_d, b_dx, mask=mask)
|
| 427 |
tl.store(dx + o_d, b_dx, mask=mask)
|
|
|
|
| 444 |
tl.store(db + i_s * D + o_d, b_db, mask=mask)
|
| 445 |
|
| 446 |
|
| 447 |
+
# Use triton only, other backends (cutlass, cute, etc.) need additional torch.compile support
|
| 448 |
+
# @dispatch
|
| 449 |
def layer_norm_gated_fwd(
|
| 450 |
x: torch.Tensor,
|
| 451 |
g: torch.Tensor,
|
|
|
|
| 453 |
bias: torch.Tensor,
|
| 454 |
activation: str = "swish",
|
| 455 |
eps: float = 1e-5,
|
| 456 |
+
residual: torch.Tensor | None = None,
|
| 457 |
+
out_dtype: torch.dtype | None = None,
|
| 458 |
+
residual_dtype: torch.dtype | None = None,
|
| 459 |
is_rms_norm: bool = False,
|
| 460 |
):
|
| 461 |
if residual is not None:
|
|
|
|
| 467 |
assert weight.shape == (D,)
|
| 468 |
if bias is not None:
|
| 469 |
assert bias.shape == (D,)
|
| 470 |
+
|
| 471 |
y = torch.empty_like(x, dtype=x.dtype if out_dtype is None else out_dtype)
|
| 472 |
if residual is not None or (residual_dtype is not None and residual_dtype != x.dtype):
|
| 473 |
residual_out = torch.empty(T, D, device=x.device, dtype=residual_dtype)
|
|
|
|
| 475 |
residual_out = None
|
| 476 |
mean = torch.empty((T,), dtype=torch.float, device=x.device) if not is_rms_norm else None
|
| 477 |
rstd = torch.empty((T,), dtype=torch.float, device=x.device)
|
| 478 |
+
|
| 479 |
MAX_FUSED_SIZE = 65536 // x.element_size()
|
| 480 |
BD = min(MAX_FUSED_SIZE, triton.next_power_of_2(D))
|
| 481 |
if D > BD:
|
| 482 |
raise RuntimeError("This layer norm doesn't support feature dim >= 64KB.")
|
|
|
|
|
|
|
| 483 |
if D <= 512:
|
| 484 |
+
# bucket token counts to limit autotuning across sequence lengths.
|
|
|
|
|
|
|
| 485 |
NB = triton.cdiv(T, 2048 * 32)
|
| 486 |
|
| 487 |
def grid(meta):
|
|
|
|
| 506 |
IS_RMS_NORM=is_rms_norm,
|
| 507 |
)
|
| 508 |
else:
|
| 509 |
+
layer_norm_gated_fwd_kernel_row[(T,)](
|
| 510 |
x=x,
|
| 511 |
g=g,
|
| 512 |
y=y,
|
|
|
|
| 526 |
return y, mean, rstd, residual_out if residual_out is not None else x
|
| 527 |
|
| 528 |
|
| 529 |
+
# Use triton only, other backends (cutlass, cute, etc.) need additional torch.compile support
|
| 530 |
+
# @dispatch
|
| 531 |
def layer_norm_gated_bwd(
|
| 532 |
dy: torch.Tensor,
|
| 533 |
x: torch.Tensor,
|
|
|
|
| 536 |
bias: torch.Tensor,
|
| 537 |
activation: str = "swish",
|
| 538 |
eps: float = 1e-5,
|
| 539 |
+
mean: torch.Tensor | None = None,
|
| 540 |
+
rstd: torch.Tensor | None = None,
|
| 541 |
+
dresidual: torch.Tensor | None = None,
|
| 542 |
has_residual: bool = False,
|
| 543 |
is_rms_norm: bool = False,
|
| 544 |
+
x_dtype: torch.dtype | None = None,
|
| 545 |
recompute_output: bool = False,
|
| 546 |
):
|
| 547 |
T, D = x.shape
|
|
|
|
| 552 |
assert weight.shape == (D,)
|
| 553 |
if bias is not None:
|
| 554 |
assert bias.shape == (D,)
|
| 555 |
+
|
| 556 |
dx = torch.empty_like(x) if x_dtype is None else torch.empty(T, D, dtype=x_dtype, device=x.device)
|
| 557 |
dg = torch.empty_like(g) if x_dtype is None else torch.empty(T, D, dtype=x_dtype, device=x.device)
|
| 558 |
dresidual_in = torch.empty_like(x) if has_residual and dx.dtype != x.dtype else None
|
| 559 |
y = torch.empty(T, D, dtype=dy.dtype, device=dy.device) if recompute_output else None
|
| 560 |
|
|
|
|
| 561 |
MAX_FUSED_SIZE = 65536 // x.element_size()
|
| 562 |
BD = min(MAX_FUSED_SIZE, triton.next_power_of_2(D))
|
| 563 |
if D > BD:
|
| 564 |
raise RuntimeError("This layer norm doesn't support feature dim >= 64KB.")
|
| 565 |
+
# cap the program count for short sequences.
|
|
|
|
|
|
|
| 566 |
NS = min(get_multiprocessor_count(x.device.index), T)
|
| 567 |
BS = math.ceil(T / NS)
|
| 568 |
|
|
|
|
| 571 |
grid = (NS,)
|
| 572 |
|
| 573 |
if D <= 512:
|
| 574 |
+
# bucket token counts to limit autotuning across sequence lengths.
|
|
|
|
|
|
|
| 575 |
NB = triton.cdiv(T, 2048 * 32)
|
| 576 |
|
| 577 |
layer_norm_gated_bwd_kernel[grid](
|
|
|
|
| 590 |
mean=mean,
|
| 591 |
rstd=rstd,
|
| 592 |
T=T,
|
|
|
|
| 593 |
BS=BS,
|
| 594 |
+
D=D,
|
| 595 |
BD=BD,
|
| 596 |
NB=NB,
|
| 597 |
ACTIVATION=activation,
|
|
|
|
| 599 |
STORE_DRESIDUAL=dresidual_in is not None,
|
| 600 |
)
|
| 601 |
else:
|
| 602 |
+
layer_norm_gated_bwd_kernel_row[grid](
|
| 603 |
x=x,
|
| 604 |
g=g,
|
| 605 |
w=weight,
|
|
|
|
| 615 |
mean=mean,
|
| 616 |
rstd=rstd,
|
| 617 |
T=T,
|
|
|
|
| 618 |
BS=BS,
|
| 619 |
+
D=D,
|
| 620 |
BD=BD,
|
| 621 |
ACTIVATION=activation,
|
| 622 |
IS_RMS_NORM=is_rms_norm,
|
|
|
|
| 624 |
)
|
| 625 |
dw = dw.sum(0).to(weight.dtype) if weight is not None else None
|
| 626 |
db = db.sum(0).to(bias.dtype) if bias is not None else None
|
| 627 |
+
# reuse dx when the residual gradient has the same dtype.
|
| 628 |
if has_residual and dx.dtype == x.dtype:
|
| 629 |
dresidual_in = dx
|
| 630 |
return (dx, dg, dw, db, dresidual_in) if not recompute_output else (dx, dg, dw, db, dresidual_in, y)
|
|
|
|
| 648 |
):
|
| 649 |
x_shape_og = x.shape
|
| 650 |
g_shape_og = g.shape
|
| 651 |
+
|
| 652 |
x = x.reshape(-1, x.shape[-1])
|
| 653 |
g = g.reshape(-1, g.shape[-1])
|
| 654 |
if residual is not None:
|
|
|
|
| 738 |
):
|
| 739 |
x_shape_og = x.shape
|
| 740 |
g_shape_og = g.shape
|
| 741 |
+
|
| 742 |
x = x.reshape(-1, x.shape[-1])
|
| 743 |
g = g.reshape(-1, g.shape[-1])
|
| 744 |
if residual is not None:
|
|
|
|
| 760 |
linear_weight = linear_weight.to(dtype)
|
| 761 |
linear_bias = linear_bias.to(dtype) if linear_bias is not None else None
|
| 762 |
out = F.linear(y.to(linear_weight.dtype), linear_weight, linear_bias)
|
| 763 |
+
# recompute y in backward to save memory.
|
| 764 |
ctx.save_for_backward(residual_out, g, norm_weight, norm_bias, linear_weight, mean, rstd)
|
| 765 |
ctx.x_shape_og = x_shape_og
|
| 766 |
ctx.g_shape_og = g_shape_og
|
|
|
|
| 828 |
residual_in_fp32: bool = False,
|
| 829 |
eps: float = 1e-6,
|
| 830 |
):
|
| 831 |
+
return LayerNormGatedFunction.apply(x, g, weight, bias, activation, residual, eps, prenorm, residual_in_fp32, False)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 832 |
|
| 833 |
|
| 834 |
def rms_norm_gated(
|
|
|
|
| 842 |
residual_in_fp32: bool = False,
|
| 843 |
eps: float = 1e-6,
|
| 844 |
):
|
| 845 |
+
return LayerNormGatedFunction.apply(x, g, weight, bias, activation, residual, eps, prenorm, residual_in_fp32, True)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 846 |
|
| 847 |
|
| 848 |
def layer_norm_swish_gate_linear(
|
|
|
|
| 909 |
eps: float = 1e-5,
|
| 910 |
device: torch.device | None = None,
|
| 911 |
dtype: torch.dtype | None = None,
|
| 912 |
+
) -> None:
|
| 913 |
factory_kwargs = {"device": device, "dtype": dtype}
|
| 914 |
super().__init__()
|
| 915 |
|
|
|
|
| 952 |
residual: torch.Tensor | None = None,
|
| 953 |
prenorm: bool = False,
|
| 954 |
residual_in_fp32: bool = False,
|
| 955 |
+
) -> torch.Tensor | tuple[torch.Tensor, torch.Tensor]:
|
| 956 |
return layer_norm_gated(
|
| 957 |
+
x=x,
|
| 958 |
+
g=g,
|
| 959 |
+
weight=self.weight,
|
| 960 |
+
bias=self.bias,
|
| 961 |
+
activation=self.activation,
|
| 962 |
residual=residual,
|
|
|
|
| 963 |
prenorm=prenorm,
|
| 964 |
residual_in_fp32=residual_in_fp32,
|
| 965 |
+
eps=self.eps,
|
| 966 |
)
|
| 967 |
|
| 968 |
|
|
|
|
| 975 |
activation: str = "swish",
|
| 976 |
device: torch.device | None = None,
|
| 977 |
dtype: torch.dtype | None = None,
|
| 978 |
+
) -> None:
|
| 979 |
factory_kwargs = {"device": device, "dtype": dtype}
|
| 980 |
super().__init__()
|
| 981 |
|
|
|
|
| 1015 |
residual: torch.Tensor | None = None,
|
| 1016 |
prenorm: bool = False,
|
| 1017 |
residual_in_fp32: bool = False,
|
| 1018 |
+
) -> torch.Tensor | tuple[torch.Tensor, torch.Tensor]:
|
| 1019 |
return rms_norm_gated(
|
| 1020 |
+
x=x,
|
| 1021 |
+
g=g,
|
| 1022 |
+
weight=self.weight,
|
| 1023 |
+
bias=self.bias,
|
| 1024 |
+
activation=self.activation,
|
| 1025 |
residual=residual,
|
|
|
|
| 1026 |
prenorm=prenorm,
|
| 1027 |
residual_in_fp32=residual_in_fp32,
|
| 1028 |
+
eps=self.eps,
|
| 1029 |
)
|
| 1030 |
|
| 1031 |
|
|
|
|
| 1038 |
eps: float = 1e-5,
|
| 1039 |
device: torch.device | None = None,
|
| 1040 |
dtype: torch.dtype | None = None,
|
| 1041 |
+
) -> None:
|
| 1042 |
super().__init__(
|
| 1043 |
hidden_size=hidden_size,
|
| 1044 |
elementwise_affine=elementwise_affine,
|
|
|
|
| 1057 |
eps: float = 1e-5,
|
| 1058 |
device: torch.device | None = None,
|
| 1059 |
dtype: torch.dtype | None = None,
|
| 1060 |
+
) -> None:
|
| 1061 |
+
super().__init__(hidden_size=hidden_size, elementwise_affine=elementwise_affine, eps=eps, device=device, dtype=dtype)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1062 |
|
| 1063 |
|
| 1064 |
class FusedLayerNormGatedLinear(nn.Module):
|
|
|
|
| 1069 |
eps: float = 1e-5,
|
| 1070 |
device: torch.device | None = None,
|
| 1071 |
dtype: torch.dtype | None = None,
|
| 1072 |
+
) -> None:
|
| 1073 |
factory_kwargs = {"device": device, "dtype": dtype}
|
| 1074 |
super().__init__()
|
| 1075 |
|
|
|
|
| 1106 |
residual: torch.Tensor | None = None,
|
| 1107 |
prenorm: bool = False,
|
| 1108 |
residual_in_fp32: bool = False,
|
| 1109 |
+
) -> torch.Tensor | tuple[torch.Tensor, torch.Tensor]:
|
| 1110 |
return layer_norm_swish_gate_linear(
|
| 1111 |
+
x=x,
|
| 1112 |
+
g=g,
|
| 1113 |
+
norm_weight=self.weight,
|
| 1114 |
+
norm_bias=self.bias,
|
| 1115 |
+
linear_weight=weight,
|
| 1116 |
+
linear_bias=bias,
|
| 1117 |
residual=residual,
|
|
|
|
| 1118 |
prenorm=prenorm,
|
| 1119 |
residual_in_fp32=residual_in_fp32,
|
| 1120 |
+
eps=self.eps,
|
| 1121 |
)
|
| 1122 |
|
| 1123 |
|
|
|
|
| 1129 |
eps: float = 1e-5,
|
| 1130 |
device: torch.device | None = None,
|
| 1131 |
dtype: torch.dtype | None = None,
|
| 1132 |
+
) -> None:
|
| 1133 |
+
super().__init__(hidden_size=hidden_size, elementwise_affine=elementwise_affine, eps=eps, device=device, dtype=dtype)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1134 |
|
| 1135 |
|
| 1136 |
class FusedRMSNormGatedLinear(nn.Module):
|
| 1137 |
def __init__(
|
| 1138 |
self,
|
| 1139 |
+
hidden_size: int,
|
| 1140 |
elementwise_affine: bool = True,
|
| 1141 |
eps: float = 1e-5,
|
| 1142 |
device: torch.device | None = None,
|
| 1143 |
dtype: torch.dtype | None = None,
|
| 1144 |
+
) -> None:
|
| 1145 |
factory_kwargs = {"device": device, "dtype": dtype}
|
| 1146 |
super().__init__()
|
| 1147 |
|
|
|
|
| 1177 |
residual: torch.Tensor | None = None,
|
| 1178 |
prenorm: bool = False,
|
| 1179 |
residual_in_fp32: bool = False,
|
| 1180 |
+
) -> torch.Tensor | tuple[torch.Tensor, torch.Tensor]:
|
| 1181 |
return rms_norm_swish_gate_linear(
|
| 1182 |
+
x=x,
|
| 1183 |
+
g=g,
|
| 1184 |
+
norm_weight=self.weight,
|
| 1185 |
+
norm_bias=self.bias,
|
| 1186 |
+
linear_weight=weight,
|
| 1187 |
+
linear_bias=bias,
|
| 1188 |
residual=residual,
|
|
|
|
| 1189 |
prenorm=prenorm,
|
| 1190 |
residual_in_fp32=residual_in_fp32,
|
| 1191 |
+
eps=self.eps,
|
| 1192 |
)
|
| 1193 |
|
| 1194 |
|
|
|
|
| 1200 |
eps: float = 1e-5,
|
| 1201 |
device: torch.device | None = None,
|
| 1202 |
dtype: torch.dtype | None = None,
|
| 1203 |
+
) -> None:
|
| 1204 |
+
super().__init__(hidden_size=hidden_size, elementwise_affine=elementwise_affine, eps=eps, device=device, dtype=dtype)
|
| 1205 |
+
|
| 1206 |
+
|
| 1207 |
+
__all__ = [
|
| 1208 |
+
'FusedLayerNormGated',
|
| 1209 |
+
'FusedLayerNormGatedLinear',
|
| 1210 |
+
'FusedLayerNormSwishGate',
|
| 1211 |
+
'FusedLayerNormSwishGateLinear',
|
| 1212 |
+
'FusedRMSNormGated',
|
| 1213 |
+
'FusedRMSNormGatedLinear',
|
| 1214 |
+
'FusedRMSNormSwishGate',
|
| 1215 |
+
'FusedRMSNormSwishGateLinear',
|
| 1216 |
+
'layer_norm_gated',
|
| 1217 |
+
'layer_norm_gated_bwd',
|
| 1218 |
+
'layer_norm_gated_fwd',
|
| 1219 |
+
'layer_norm_swish_gate_linear',
|
| 1220 |
+
'rms_norm_gated',
|
| 1221 |
+
'rms_norm_swish_gate_linear',
|
| 1222 |
+
]
|