tiagomonteiro0715 commited on
Commit ·
fcfe221
1
Parent(s): 490d9fe
migrate to new huggingface/kernels builder schema
Browse files- build.toml +9 -3
- build/torch-cuda/_kernel.py +4 -4
- build/torch-cuda/_ops.py +33 -3
- build/torch-cuda/metadata.json +28 -1
- build/torch-cuda/my_softmax_function/__init__.py +0 -26
- flake.lock +35 -13
- flake.nix +5 -2
- torch-ext/my_softmax_function/_kernel.py +4 -4
build.toml
CHANGED
|
@@ -1,10 +1,16 @@
|
|
|
|
|
|
|
|
|
|
|
| 1 |
[general]
|
| 2 |
-
name = "
|
|
|
|
|
|
|
|
|
|
| 3 |
backends = ["cuda"]
|
| 4 |
|
| 5 |
[general.cuda]
|
|
|
|
| 6 |
minver = "12.8"
|
| 7 |
python-depends = ["nvidia-cutlass-dsl"]
|
| 8 |
|
| 9 |
-
[torch]
|
| 10 |
-
src = []
|
|
|
|
| 1 |
+
# Hugging Face kernel manifest (new huggingface/kernels schema).
|
| 2 |
+
# Pure-Python kernel (CUTLASS Python DSL, JIT-compiled on the GPU at runtime):
|
| 3 |
+
# no compiled sources -> declared with [torch-noarch]. CUDA-only (CUTLASS is NVIDIA).
|
| 4 |
[general]
|
| 5 |
+
name = "my-softmax-function"
|
| 6 |
+
version = 1
|
| 7 |
+
edition = 5
|
| 8 |
+
license = "Apache-2.0"
|
| 9 |
backends = ["cuda"]
|
| 10 |
|
| 11 |
[general.cuda]
|
| 12 |
+
# nvidia-cutlass-dsl 4.3.0 requires CUDA >= 12.8.
|
| 13 |
minver = "12.8"
|
| 14 |
python-depends = ["nvidia-cutlass-dsl"]
|
| 15 |
|
| 16 |
+
[torch-noarch]
|
|
|
build/torch-cuda/_kernel.py
CHANGED
|
@@ -10,12 +10,11 @@ import math
|
|
| 10 |
import torch
|
| 11 |
from cutlass.cute.runtime import from_dlpack
|
| 12 |
|
|
|
|
| 13 |
from .attention_v3 import solve
|
| 14 |
|
| 15 |
-
_OP_NAME = "my_softmax_function::softmax_attention"
|
| 16 |
|
| 17 |
-
|
| 18 |
-
@torch.library.custom_op(_OP_NAME, mutates_args=())
|
| 19 |
def softmax_attention(
|
| 20 |
Q: torch.Tensor, # (M, d)
|
| 21 |
K: torch.Tensor, # (N, d)
|
|
@@ -65,4 +64,5 @@ def attention(Q, K, V, scale=None):
|
|
| 65 |
"""Convenience entry point with a default 1/sqrt(d) scale."""
|
| 66 |
if scale is None:
|
| 67 |
scale = 1.0 / math.sqrt(Q.shape[-1])
|
| 68 |
-
|
|
|
|
|
|
| 10 |
import torch
|
| 11 |
from cutlass.cute.runtime import from_dlpack
|
| 12 |
|
| 13 |
+
from ._ops import add_op_namespace_prefix
|
| 14 |
from .attention_v3 import solve
|
| 15 |
|
|
|
|
| 16 |
|
| 17 |
+
@torch.library.custom_op(add_op_namespace_prefix("softmax_attention"), mutates_args=())
|
|
|
|
| 18 |
def softmax_attention(
|
| 19 |
Q: torch.Tensor, # (M, d)
|
| 20 |
K: torch.Tensor, # (N, d)
|
|
|
|
| 64 |
"""Convenience entry point with a default 1/sqrt(d) scale."""
|
| 65 |
if scale is None:
|
| 66 |
scale = 1.0 / math.sqrt(Q.shape[-1])
|
| 67 |
+
# Call the registered op directly (its namespace is build-unique).
|
| 68 |
+
return softmax_attention(Q, K, V, scale)
|
build/torch-cuda/_ops.py
CHANGED
|
@@ -1,8 +1,38 @@
|
|
| 1 |
import torch
|
| 2 |
-
ops = torch.ops._my_softmax_function_2af76fc
|
| 3 |
|
| 4 |
-
def
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 5 |
"""
|
| 6 |
Prefix op by namespace.
|
| 7 |
"""
|
| 8 |
-
return f"
|
|
|
|
| 1 |
import torch
|
|
|
|
| 2 |
|
| 3 |
+
def get_backend() -> str:
|
| 4 |
+
"""Detect the backend by inspecting torch."""
|
| 5 |
+
import torch
|
| 6 |
+
|
| 7 |
+
if hasattr(torch, "neuron"):
|
| 8 |
+
# Needs to be sorted before specific Torch builds, since Neuron
|
| 9 |
+
# extension can be loaded into e.g. CUDA Torch builds.
|
| 10 |
+
return "neuron"
|
| 11 |
+
elif torch.version.cuda is not None:
|
| 12 |
+
return "cuda"
|
| 13 |
+
elif torch.version.hip is not None:
|
| 14 |
+
return "rocm"
|
| 15 |
+
elif torch.backends.mps.is_available():
|
| 16 |
+
return "metal"
|
| 17 |
+
elif hasattr(torch.version, "xpu") and torch.version.xpu is not None:
|
| 18 |
+
return "xpu"
|
| 19 |
+
else:
|
| 20 |
+
return "cpu"
|
| 21 |
+
|
| 22 |
+
|
| 23 |
+
def _find_ops_name() -> str:
|
| 24 |
+
kernel_name = "my_softmax_function"
|
| 25 |
+
unique_id = "490d9fe_dirty"
|
| 26 |
+
backend = get_backend()
|
| 27 |
+
return f"_{kernel_name}_{backend}_{unique_id}"
|
| 28 |
+
|
| 29 |
+
|
| 30 |
+
_OPS_NAME = _find_ops_name()
|
| 31 |
+
|
| 32 |
+
ops = getattr(torch.ops, _OPS_NAME)
|
| 33 |
+
|
| 34 |
+
def add_op_namespace_prefix(op_name: str) -> str:
|
| 35 |
"""
|
| 36 |
Prefix op by namespace.
|
| 37 |
"""
|
| 38 |
+
return f"{_OPS_NAME}::{op_name}"
|
build/torch-cuda/metadata.json
CHANGED
|
@@ -1,5 +1,32 @@
|
|
| 1 |
{
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2 |
"python-depends": [
|
| 3 |
"nvidia-cutlass-dsl"
|
| 4 |
-
]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 5 |
}
|
|
|
|
| 1 |
{
|
| 2 |
+
"name": "my-softmax-function",
|
| 3 |
+
"id": "_my_softmax_function_cuda_490d9fe_dirty",
|
| 4 |
+
"version": 1,
|
| 5 |
+
"license": "Apache-2.0",
|
| 6 |
"python-depends": [
|
| 7 |
"nvidia-cutlass-dsl"
|
| 8 |
+
],
|
| 9 |
+
"backend": {
|
| 10 |
+
"type": "cuda"
|
| 11 |
+
},
|
| 12 |
+
"digest": {
|
| 13 |
+
"algorithm": "sha256",
|
| 14 |
+
"files": {
|
| 15 |
+
"__init__.py": "ZpvyIhcU8bz4Xcc1WhVskt3WR3Yx9CCzS8+Jl1DOXGU=",
|
| 16 |
+
"_kernel.py": "xDfkK2UVoOoZY8Jn4VtzTxrzdo6MfXVm72qu2S+/jp8=",
|
| 17 |
+
"_ops.py": "ZkMq9OCa4I7SzsNvw++4/jnPxnmILtflnvy5frJ1Pgc=",
|
| 18 |
+
"attention_v3.py": "xWyf2XnBmPKuOe5D6h8/3S3QwQXpbYFZTYCRh49Fkso="
|
| 19 |
+
}
|
| 20 |
+
},
|
| 21 |
+
"provenance": {
|
| 22 |
+
"kernel-builder": {
|
| 23 |
+
"version": "0.17.0-dev0",
|
| 24 |
+
"sha": "d0610aa58db33b142c86b59598a2a1c730f52996",
|
| 25 |
+
"dirty": false
|
| 26 |
+
},
|
| 27 |
+
"kernel": {
|
| 28 |
+
"sha": "490d9fe259aa1f38cdfd8c9646791796518182ee",
|
| 29 |
+
"dirty": true
|
| 30 |
+
}
|
| 31 |
+
}
|
| 32 |
}
|
build/torch-cuda/my_softmax_function/__init__.py
DELETED
|
@@ -1,26 +0,0 @@
|
|
| 1 |
-
import ctypes
|
| 2 |
-
import sys
|
| 3 |
-
|
| 4 |
-
import importlib
|
| 5 |
-
from pathlib import Path
|
| 6 |
-
from types import ModuleType
|
| 7 |
-
|
| 8 |
-
def _import_from_path(file_path: Path) -> ModuleType:
|
| 9 |
-
# We cannot use the module name as-is, after adding it to `sys.modules`,
|
| 10 |
-
# it would also be used for other imports. So, we make a module name that
|
| 11 |
-
# depends on the path for it to be unique using the hex-encoded hash of
|
| 12 |
-
# the path.
|
| 13 |
-
path_hash = "{:x}".format(ctypes.c_size_t(hash(file_path.absolute())).value)
|
| 14 |
-
module_name = path_hash
|
| 15 |
-
spec = importlib.util.spec_from_file_location(module_name, file_path)
|
| 16 |
-
if spec is None:
|
| 17 |
-
raise ImportError(f"Cannot load spec for {module_name} from {file_path}")
|
| 18 |
-
module = importlib.util.module_from_spec(spec)
|
| 19 |
-
if module is None:
|
| 20 |
-
raise ImportError(f"Cannot load module {module_name} from spec")
|
| 21 |
-
sys.modules[module_name] = module
|
| 22 |
-
spec.loader.exec_module(module) # type: ignore
|
| 23 |
-
return module
|
| 24 |
-
|
| 25 |
-
|
| 26 |
-
globals().update(vars(_import_from_path(Path(__file__).parent.parent / "__init__.py")))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
flake.lock
CHANGED
|
@@ -2,11 +2,11 @@
|
|
| 2 |
"nodes": {
|
| 3 |
"flake-compat": {
|
| 4 |
"locked": {
|
| 5 |
-
"lastModified":
|
| 6 |
-
"narHash": "sha256-
|
| 7 |
"owner": "edolstra",
|
| 8 |
"repo": "flake-compat",
|
| 9 |
-
"rev": "
|
| 10 |
"type": "github"
|
| 11 |
},
|
| 12 |
"original": {
|
|
@@ -37,35 +37,36 @@
|
|
| 37 |
"inputs": {
|
| 38 |
"flake-compat": "flake-compat",
|
| 39 |
"flake-utils": "flake-utils",
|
| 40 |
-
"nixpkgs": "nixpkgs"
|
|
|
|
| 41 |
},
|
| 42 |
"locked": {
|
| 43 |
-
"lastModified":
|
| 44 |
-
"narHash": "sha256-
|
| 45 |
"owner": "huggingface",
|
| 46 |
-
"repo": "
|
| 47 |
-
"rev": "
|
| 48 |
"type": "github"
|
| 49 |
},
|
| 50 |
"original": {
|
| 51 |
"owner": "huggingface",
|
| 52 |
-
"repo": "
|
| 53 |
"type": "github"
|
| 54 |
}
|
| 55 |
},
|
| 56 |
"nixpkgs": {
|
| 57 |
"locked": {
|
| 58 |
-
"lastModified":
|
| 59 |
-
"narHash": "sha256-
|
| 60 |
"owner": "NixOS",
|
| 61 |
"repo": "nixpkgs",
|
| 62 |
-
"rev": "
|
| 63 |
"type": "github"
|
| 64 |
},
|
| 65 |
"original": {
|
| 66 |
"owner": "NixOS",
|
| 67 |
-
"ref": "nixos-unstable-small",
|
| 68 |
"repo": "nixpkgs",
|
|
|
|
| 69 |
"type": "github"
|
| 70 |
}
|
| 71 |
},
|
|
@@ -74,6 +75,27 @@
|
|
| 74 |
"kernel-builder": "kernel-builder"
|
| 75 |
}
|
| 76 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 77 |
"systems": {
|
| 78 |
"locked": {
|
| 79 |
"lastModified": 1681028828,
|
|
|
|
| 2 |
"nodes": {
|
| 3 |
"flake-compat": {
|
| 4 |
"locked": {
|
| 5 |
+
"lastModified": 1767039857,
|
| 6 |
+
"narHash": "sha256-vNpUSpF5Nuw8xvDLj2KCwwksIbjua2LZCqhV1LNRDns=",
|
| 7 |
"owner": "edolstra",
|
| 8 |
"repo": "flake-compat",
|
| 9 |
+
"rev": "5edf11c44bc78a0d334f6334cdaf7d60d732daab",
|
| 10 |
"type": "github"
|
| 11 |
},
|
| 12 |
"original": {
|
|
|
|
| 37 |
"inputs": {
|
| 38 |
"flake-compat": "flake-compat",
|
| 39 |
"flake-utils": "flake-utils",
|
| 40 |
+
"nixpkgs": "nixpkgs",
|
| 41 |
+
"rust-overlay": "rust-overlay"
|
| 42 |
},
|
| 43 |
"locked": {
|
| 44 |
+
"lastModified": 1785427612,
|
| 45 |
+
"narHash": "sha256-hUFEwQKDjVHw9v6xgC6Lx402TYfUA8zXEi8hDE/F4y0=",
|
| 46 |
"owner": "huggingface",
|
| 47 |
+
"repo": "kernels",
|
| 48 |
+
"rev": "d0610aa58db33b142c86b59598a2a1c730f52996",
|
| 49 |
"type": "github"
|
| 50 |
},
|
| 51 |
"original": {
|
| 52 |
"owner": "huggingface",
|
| 53 |
+
"repo": "kernels",
|
| 54 |
"type": "github"
|
| 55 |
}
|
| 56 |
},
|
| 57 |
"nixpkgs": {
|
| 58 |
"locked": {
|
| 59 |
+
"lastModified": 1783284758,
|
| 60 |
+
"narHash": "sha256-tiQ8/qi8I45OOaBBYlVbXoAVkeQzvvTQOv5I45rMw5o=",
|
| 61 |
"owner": "NixOS",
|
| 62 |
"repo": "nixpkgs",
|
| 63 |
+
"rev": "ec1a11210589d294f0ac99d3290a27e6c73dfa1d",
|
| 64 |
"type": "github"
|
| 65 |
},
|
| 66 |
"original": {
|
| 67 |
"owner": "NixOS",
|
|
|
|
| 68 |
"repo": "nixpkgs",
|
| 69 |
+
"rev": "ec1a11210589d294f0ac99d3290a27e6c73dfa1d",
|
| 70 |
"type": "github"
|
| 71 |
}
|
| 72 |
},
|
|
|
|
| 75 |
"kernel-builder": "kernel-builder"
|
| 76 |
}
|
| 77 |
},
|
| 78 |
+
"rust-overlay": {
|
| 79 |
+
"inputs": {
|
| 80 |
+
"nixpkgs": [
|
| 81 |
+
"kernel-builder",
|
| 82 |
+
"nixpkgs"
|
| 83 |
+
]
|
| 84 |
+
},
|
| 85 |
+
"locked": {
|
| 86 |
+
"lastModified": 1783320166,
|
| 87 |
+
"narHash": "sha256-l7C/OsjcnWDOk2K3ssj+SBduwL67LashjBqis9+t468=",
|
| 88 |
+
"owner": "oxalica",
|
| 89 |
+
"repo": "rust-overlay",
|
| 90 |
+
"rev": "20ee15370c9256669d66968b89ee20a4b0a4e673",
|
| 91 |
+
"type": "github"
|
| 92 |
+
},
|
| 93 |
+
"original": {
|
| 94 |
+
"owner": "oxalica",
|
| 95 |
+
"repo": "rust-overlay",
|
| 96 |
+
"type": "github"
|
| 97 |
+
}
|
| 98 |
+
},
|
| 99 |
"systems": {
|
| 100 |
"locked": {
|
| 101 |
"lastModified": 1681028828,
|
flake.nix
CHANGED
|
@@ -2,7 +2,9 @@
|
|
| 2 |
description = "my_softmax_function — fused softmax-attention kernel";
|
| 3 |
|
| 4 |
inputs = {
|
| 5 |
-
kernel-builder
|
|
|
|
|
|
|
| 6 |
};
|
| 7 |
|
| 8 |
outputs =
|
|
@@ -10,7 +12,8 @@
|
|
| 10 |
self,
|
| 11 |
kernel-builder,
|
| 12 |
}:
|
| 13 |
-
|
|
|
|
| 14 |
inherit self;
|
| 15 |
path = ./.;
|
| 16 |
};
|
|
|
|
| 2 |
description = "my_softmax_function — fused softmax-attention kernel";
|
| 3 |
|
| 4 |
inputs = {
|
| 5 |
+
# New merged repo (kernel-builder folded into huggingface/kernels).
|
| 6 |
+
# Its metadata schema matches the current `kernels` loader library.
|
| 7 |
+
kernel-builder.url = "github:huggingface/kernels";
|
| 8 |
};
|
| 9 |
|
| 10 |
outputs =
|
|
|
|
| 12 |
self,
|
| 13 |
kernel-builder,
|
| 14 |
}:
|
| 15 |
+
# genFlakeOutputs was renamed to genKernelFlakeOutputs in the new repo.
|
| 16 |
+
kernel-builder.lib.genKernelFlakeOutputs {
|
| 17 |
inherit self;
|
| 18 |
path = ./.;
|
| 19 |
};
|
torch-ext/my_softmax_function/_kernel.py
CHANGED
|
@@ -10,12 +10,11 @@ import math
|
|
| 10 |
import torch
|
| 11 |
from cutlass.cute.runtime import from_dlpack
|
| 12 |
|
|
|
|
| 13 |
from .attention_v3 import solve
|
| 14 |
|
| 15 |
-
_OP_NAME = "my_softmax_function::softmax_attention"
|
| 16 |
|
| 17 |
-
|
| 18 |
-
@torch.library.custom_op(_OP_NAME, mutates_args=())
|
| 19 |
def softmax_attention(
|
| 20 |
Q: torch.Tensor, # (M, d)
|
| 21 |
K: torch.Tensor, # (N, d)
|
|
@@ -65,4 +64,5 @@ def attention(Q, K, V, scale=None):
|
|
| 65 |
"""Convenience entry point with a default 1/sqrt(d) scale."""
|
| 66 |
if scale is None:
|
| 67 |
scale = 1.0 / math.sqrt(Q.shape[-1])
|
| 68 |
-
|
|
|
|
|
|
| 10 |
import torch
|
| 11 |
from cutlass.cute.runtime import from_dlpack
|
| 12 |
|
| 13 |
+
from ._ops import add_op_namespace_prefix
|
| 14 |
from .attention_v3 import solve
|
| 15 |
|
|
|
|
| 16 |
|
| 17 |
+
@torch.library.custom_op(add_op_namespace_prefix("softmax_attention"), mutates_args=())
|
|
|
|
| 18 |
def softmax_attention(
|
| 19 |
Q: torch.Tensor, # (M, d)
|
| 20 |
K: torch.Tensor, # (N, d)
|
|
|
|
| 64 |
"""Convenience entry point with a default 1/sqrt(d) scale."""
|
| 65 |
if scale is None:
|
| 66 |
scale = 1.0 / math.sqrt(Q.shape[-1])
|
| 67 |
+
# Call the registered op directly (its namespace is build-unique).
|
| 68 |
+
return softmax_attention(Q, K, V, scale)
|