phanerozoic commited on
Commit
905e624
·
verified ·
1 Parent(s): be4c1e1

Uploaded using `kernel-builder`.

Browse files
Files changed (45) hide show
  1. build/torch211-cxx11-cu126-x86_64-linux/__init__.py +114 -0
  2. build/torch211-cxx11-cu126-x86_64-linux/_binary_gemm_cuda_31ce78e.abi3.so +3 -0
  3. build/torch211-cxx11-cu126-x86_64-linux/_ops.py +9 -0
  4. build/torch211-cxx11-cu126-x86_64-linux/binary_gemm/__init__.py +26 -0
  5. build/torch211-cxx11-cu126-x86_64-linux/metadata.json +36 -0
  6. build/torch211-cxx11-cu128-x86_64-linux/__init__.py +114 -0
  7. build/torch211-cxx11-cu128-x86_64-linux/_binary_gemm_cuda_31ce78e.abi3.so +3 -0
  8. build/torch211-cxx11-cu128-x86_64-linux/_ops.py +9 -0
  9. build/torch211-cxx11-cu128-x86_64-linux/binary_gemm/__init__.py +26 -0
  10. build/torch211-cxx11-cu128-x86_64-linux/metadata.json +38 -0
  11. build/torch211-cxx11-cu130-x86_64-linux/__init__.py +114 -0
  12. build/torch211-cxx11-cu130-x86_64-linux/_binary_gemm_cuda_31ce78e.abi3.so +3 -0
  13. build/torch211-cxx11-cu130-x86_64-linux/_ops.py +9 -0
  14. build/torch211-cxx11-cu130-x86_64-linux/binary_gemm/__init__.py +26 -0
  15. build/torch211-cxx11-cu130-x86_64-linux/metadata.json +38 -0
  16. build/torch212-cxx11-cu126-x86_64-linux/__init__.py +114 -0
  17. build/torch212-cxx11-cu126-x86_64-linux/_binary_gemm_cuda_31ce78e.abi3.so +3 -0
  18. build/torch212-cxx11-cu126-x86_64-linux/_ops.py +9 -0
  19. build/torch212-cxx11-cu126-x86_64-linux/binary_gemm/__init__.py +26 -0
  20. build/torch212-cxx11-cu126-x86_64-linux/metadata.json +36 -0
  21. build/torch212-cxx11-cu130-x86_64-linux/__init__.py +114 -0
  22. build/torch212-cxx11-cu130-x86_64-linux/_binary_gemm_cuda_31ce78e.abi3.so +3 -0
  23. build/torch212-cxx11-cu130-x86_64-linux/_ops.py +9 -0
  24. build/torch212-cxx11-cu130-x86_64-linux/binary_gemm/__init__.py +26 -0
  25. build/torch212-cxx11-cu130-x86_64-linux/metadata.json +38 -0
  26. build/torch212-cxx11-cu132-x86_64-linux/__init__.py +114 -0
  27. build/torch212-cxx11-cu132-x86_64-linux/_binary_gemm_cuda_31ce78e.abi3.so +3 -0
  28. build/torch212-cxx11-cu132-x86_64-linux/_ops.py +9 -0
  29. build/torch212-cxx11-cu132-x86_64-linux/binary_gemm/__init__.py +26 -0
  30. build/torch212-cxx11-cu132-x86_64-linux/metadata.json +38 -0
  31. build/torch213-cxx11-cu126-x86_64-linux/__init__.py +114 -0
  32. build/torch213-cxx11-cu126-x86_64-linux/_binary_gemm_cuda_31ce78e.abi3.so +3 -0
  33. build/torch213-cxx11-cu126-x86_64-linux/_ops.py +9 -0
  34. build/torch213-cxx11-cu126-x86_64-linux/binary_gemm/__init__.py +26 -0
  35. build/torch213-cxx11-cu126-x86_64-linux/metadata.json +36 -0
  36. build/torch213-cxx11-cu130-x86_64-linux/__init__.py +114 -0
  37. build/torch213-cxx11-cu130-x86_64-linux/_binary_gemm_cuda_31ce78e.abi3.so +3 -0
  38. build/torch213-cxx11-cu130-x86_64-linux/_ops.py +9 -0
  39. build/torch213-cxx11-cu130-x86_64-linux/binary_gemm/__init__.py +26 -0
  40. build/torch213-cxx11-cu130-x86_64-linux/metadata.json +38 -0
  41. build/torch213-cxx11-cu132-x86_64-linux/__init__.py +114 -0
  42. build/torch213-cxx11-cu132-x86_64-linux/_binary_gemm_cuda_31ce78e.abi3.so +3 -0
  43. build/torch213-cxx11-cu132-x86_64-linux/_ops.py +9 -0
  44. build/torch213-cxx11-cu132-x86_64-linux/binary_gemm/__init__.py +26 -0
  45. build/torch213-cxx11-cu132-x86_64-linux/metadata.json +38 -0
build/torch211-cxx11-cu126-x86_64-linux/__init__.py ADDED
@@ -0,0 +1,114 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """binary-gemm: W1A8 matrix products for binary-weight language models.
2
+
3
+ Each weight is one bit meaning +1 or -1, with one fp16 scale per group of G
4
+ weights: at G = 128 that is 1.125 effective bits, against 2 bits for a ternary
5
+ layer and 16 for bf16. Activations are quantized per token to int8.
6
+
7
+ Binary weights are not a special case of ternary. Writing the stored bit as
8
+ b = (w + 1) / 2, the inner product is 2 * sum_{b_i = 1} a_i - sum_i a_i, so the
9
+ weight is never materialized as a number. The kernel resolves four weights at a
10
+ time through a nibble table feeding __dp4a.
11
+
12
+ Ternary companions on the Hub: phanerozoic/bitnet-tc (CUDA),
13
+ phanerozoic/bitnet-cpu (CPU).
14
+ """
15
+ from typing import Optional, Tuple
16
+
17
+ import torch
18
+
19
+ from ._ops import ops
20
+
21
+ __all__ = [
22
+ "pack_weights", "unpack_weights", "quantize_activation", "binary_gemm",
23
+ "binary_linear", "BinaryLinear",
24
+ ]
25
+
26
+ GROUP = 128
27
+
28
+
29
+ def pack_weights(w: torch.Tensor) -> torch.Tensor:
30
+ """Pack a ``{-1, +1}`` int8 ``[N, K]`` matrix to ``[N, K//32]`` int32.
31
+
32
+ Bit j of word i holds weight ``32*i + j``: set means +1, clear means -1.
33
+ Zeros are treated as -1, so a ternary tensor will not round-trip.
34
+ """
35
+ return ops.pack_weights(w.contiguous().to(torch.int8))
36
+
37
+
38
+ def unpack_weights(wq: torch.Tensor, K: int) -> torch.Tensor:
39
+ """Inverse of :func:`pack_weights`, for tests and for a reference path."""
40
+ bits = wq.to(torch.int32)
41
+ idx = torch.arange(32, device=wq.device, dtype=torch.int32)
42
+ out = ((bits.unsqueeze(-1) >> idx) & 1).to(torch.int8)
43
+ return (out.reshape(wq.shape[0], -1)[:, :K] * 2 - 1)
44
+
45
+
46
+ def quantize_activation(x: torch.Tensor) -> Tuple[torch.Tensor, torch.Tensor]:
47
+ """bf16 ``[..., K]`` -> (int8 ``[M, K]``, fp32 per-token scale ``[M]``)."""
48
+ q, s = ops.quantize_activation(x.contiguous().to(torch.bfloat16))
49
+ return q, s
50
+
51
+
52
+ def binary_gemm(act_q: torch.Tensor, act_scale: torch.Tensor, wq: torch.Tensor,
53
+ wscale: torch.Tensor, bias: Optional[torch.Tensor] = None,
54
+ group_size: int = GROUP) -> torch.Tensor:
55
+ """int8 activations times packed binary weights -> bf16 ``[M, N]``."""
56
+ return ops.binary_gemm(act_q, act_scale, wq, wscale, bias, group_size)
57
+
58
+
59
+ def binary_linear(x: torch.Tensor, wq: torch.Tensor, wscale: torch.Tensor,
60
+ bias: Optional[torch.Tensor] = None,
61
+ group_size: int = GROUP) -> torch.Tensor:
62
+ """One-shot forward: quantize the activation, then the packed product.
63
+ Trailing batch dimensions are preserved."""
64
+ shape = x.shape[:-1]
65
+ q, s = quantize_activation(x)
66
+ out = binary_gemm(q, s, wq, wscale, bias, group_size)
67
+ return out.reshape(*shape, out.shape[-1])
68
+
69
+
70
+ class BinaryLinear(torch.nn.Module):
71
+ """Drop-in for a binary-weight ``nn.Linear``. Holds packed weights and their
72
+ group scales; nothing is stored at higher precision."""
73
+
74
+ def __init__(self, in_features: int, out_features: int, bias: bool = False,
75
+ group_size: int = GROUP, device=None):
76
+ super().__init__()
77
+ assert in_features % 32 == 0, "in_features must be a multiple of 32"
78
+ assert in_features % group_size == 0, "in_features must be a multiple of group_size"
79
+ self.in_features = in_features
80
+ self.out_features = out_features
81
+ self.group_size = group_size
82
+ self.register_buffer(
83
+ "wq", torch.zeros(out_features, in_features // 32, dtype=torch.int32,
84
+ device=device))
85
+ self.register_buffer(
86
+ "wscale", torch.ones(out_features, in_features // group_size,
87
+ dtype=torch.float16, device=device))
88
+ self.bias = torch.nn.Parameter(
89
+ torch.zeros(out_features, device=device)) if bias else None
90
+
91
+ @classmethod
92
+ def from_dense(cls, lin: torch.nn.Linear, group_size: int = GROUP) -> "BinaryLinear":
93
+ """Binarize an existing linear by sign, with the group scale set to the
94
+ group's mean absolute weight, which is the scale that minimizes squared
95
+ error for a sign-quantized group."""
96
+ W = lin.weight.data
97
+ N, K = W.shape
98
+ m = cls(K, N, bias=lin.bias is not None, group_size=group_size,
99
+ device=W.device)
100
+ signs = torch.where(W >= 0, 1, -1).to(torch.int8)
101
+ m.wq.copy_(pack_weights(signs))
102
+ m.wscale.copy_(W.reshape(N, K // group_size, group_size).abs().mean(-1)
103
+ .to(torch.float16))
104
+ if lin.bias is not None:
105
+ m.bias.data.copy_(lin.bias.data)
106
+ return m
107
+
108
+ def forward(self, x: torch.Tensor) -> torch.Tensor:
109
+ return binary_linear(x, self.wq, self.wscale, self.bias, self.group_size)
110
+
111
+ def extra_repr(self) -> str:
112
+ bits = 1 + 16 / self.group_size
113
+ return (f"in_features={self.in_features}, out_features={self.out_features}, "
114
+ f"group_size={self.group_size}, effective_bits={bits:.3f}")
build/torch211-cxx11-cu126-x86_64-linux/_binary_gemm_cuda_31ce78e.abi3.so ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:b0726f6e858bd28e6f7afec48f47ccb1b74cf5e0213fd015036b1b5bdf9d03d7
3
+ size 433992
build/torch211-cxx11-cu126-x86_64-linux/_ops.py ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ import torch
2
+ from . import _binary_gemm_cuda_31ce78e
3
+ ops = torch.ops._binary_gemm_cuda_31ce78e
4
+
5
+ def add_op_namespace_prefix(op_name: str):
6
+ """
7
+ Prefix op by namespace.
8
+ """
9
+ return f"_binary_gemm_cuda_31ce78e::{op_name}"
build/torch211-cxx11-cu126-x86_64-linux/binary_gemm/__init__.py ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import ctypes
2
+ import importlib.util
3
+ import sys
4
+ from pathlib import Path
5
+ from types import ModuleType
6
+
7
+
8
+ def _import_from_path(file_path: Path) -> ModuleType:
9
+ # We cannot use the module name as-is, after adding it to `sys.modules`,
10
+ # it would also be used for other imports. So, we make a module name that
11
+ # depends on the path for it to be unique using the hex-encoded hash of
12
+ # the path.
13
+ path_hash = "{:x}".format(ctypes.c_size_t(hash(file_path.absolute())).value)
14
+ module_name = path_hash
15
+ spec = importlib.util.spec_from_file_location(module_name, file_path)
16
+ if spec is None:
17
+ raise ImportError(f"Cannot load spec for {module_name} from {file_path}")
18
+ module = importlib.util.module_from_spec(spec)
19
+ if module is None:
20
+ raise ImportError(f"Cannot load module {module_name} from spec")
21
+ sys.modules[module_name] = module
22
+ spec.loader.exec_module(module) # type: ignore
23
+ return module
24
+
25
+
26
+ globals().update(vars(_import_from_path(Path(__file__).parent.parent / "__init__.py")))
build/torch211-cxx11-cu126-x86_64-linux/metadata.json ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "binary-gemm",
3
+ "id": "_binary_gemm_cuda_31ce78e",
4
+ "version": 1,
5
+ "license": "Apache-2.0",
6
+ "python-depends": [],
7
+ "backend": {
8
+ "type": "cuda",
9
+ "archs": [
10
+ "8.0",
11
+ "8.6",
12
+ "8.9",
13
+ "9.0"
14
+ ]
15
+ },
16
+ "digest": {
17
+ "algorithm": "sha256",
18
+ "files": {
19
+ "__init__.py": "fwn5WUojHrxLQwNl70+IAx7FZfHJQI9O+Zp5h4F+n7Y=",
20
+ "_binary_gemm_cuda_31ce78e.abi3.so": "sHJvboWL0o5vev7Ej0fMsbdM9eAhP9AVA2sbW9+dA9c=",
21
+ "_ops.py": "cGdYjoXrblpZs8DIqLlPArXWztTZ+wWrveEjvYq+5/0=",
22
+ "binary_gemm/__init__.py": "DFYPlrhXwYjEqCl/8n0SmWGZV8NFml5DPhMjKfv98GY="
23
+ }
24
+ },
25
+ "provenance": {
26
+ "kernel-builder": {
27
+ "version": "0.17.0-dev0",
28
+ "sha": "19aaa6421e674e9fecc352bbae6eab81d19a6bf4",
29
+ "dirty": false
30
+ },
31
+ "kernel": {
32
+ "sha": "31ce78ecfe5b53cd413fd76785b351410c1f610a",
33
+ "dirty": false
34
+ }
35
+ }
36
+ }
build/torch211-cxx11-cu128-x86_64-linux/__init__.py ADDED
@@ -0,0 +1,114 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """binary-gemm: W1A8 matrix products for binary-weight language models.
2
+
3
+ Each weight is one bit meaning +1 or -1, with one fp16 scale per group of G
4
+ weights: at G = 128 that is 1.125 effective bits, against 2 bits for a ternary
5
+ layer and 16 for bf16. Activations are quantized per token to int8.
6
+
7
+ Binary weights are not a special case of ternary. Writing the stored bit as
8
+ b = (w + 1) / 2, the inner product is 2 * sum_{b_i = 1} a_i - sum_i a_i, so the
9
+ weight is never materialized as a number. The kernel resolves four weights at a
10
+ time through a nibble table feeding __dp4a.
11
+
12
+ Ternary companions on the Hub: phanerozoic/bitnet-tc (CUDA),
13
+ phanerozoic/bitnet-cpu (CPU).
14
+ """
15
+ from typing import Optional, Tuple
16
+
17
+ import torch
18
+
19
+ from ._ops import ops
20
+
21
+ __all__ = [
22
+ "pack_weights", "unpack_weights", "quantize_activation", "binary_gemm",
23
+ "binary_linear", "BinaryLinear",
24
+ ]
25
+
26
+ GROUP = 128
27
+
28
+
29
+ def pack_weights(w: torch.Tensor) -> torch.Tensor:
30
+ """Pack a ``{-1, +1}`` int8 ``[N, K]`` matrix to ``[N, K//32]`` int32.
31
+
32
+ Bit j of word i holds weight ``32*i + j``: set means +1, clear means -1.
33
+ Zeros are treated as -1, so a ternary tensor will not round-trip.
34
+ """
35
+ return ops.pack_weights(w.contiguous().to(torch.int8))
36
+
37
+
38
+ def unpack_weights(wq: torch.Tensor, K: int) -> torch.Tensor:
39
+ """Inverse of :func:`pack_weights`, for tests and for a reference path."""
40
+ bits = wq.to(torch.int32)
41
+ idx = torch.arange(32, device=wq.device, dtype=torch.int32)
42
+ out = ((bits.unsqueeze(-1) >> idx) & 1).to(torch.int8)
43
+ return (out.reshape(wq.shape[0], -1)[:, :K] * 2 - 1)
44
+
45
+
46
+ def quantize_activation(x: torch.Tensor) -> Tuple[torch.Tensor, torch.Tensor]:
47
+ """bf16 ``[..., K]`` -> (int8 ``[M, K]``, fp32 per-token scale ``[M]``)."""
48
+ q, s = ops.quantize_activation(x.contiguous().to(torch.bfloat16))
49
+ return q, s
50
+
51
+
52
+ def binary_gemm(act_q: torch.Tensor, act_scale: torch.Tensor, wq: torch.Tensor,
53
+ wscale: torch.Tensor, bias: Optional[torch.Tensor] = None,
54
+ group_size: int = GROUP) -> torch.Tensor:
55
+ """int8 activations times packed binary weights -> bf16 ``[M, N]``."""
56
+ return ops.binary_gemm(act_q, act_scale, wq, wscale, bias, group_size)
57
+
58
+
59
+ def binary_linear(x: torch.Tensor, wq: torch.Tensor, wscale: torch.Tensor,
60
+ bias: Optional[torch.Tensor] = None,
61
+ group_size: int = GROUP) -> torch.Tensor:
62
+ """One-shot forward: quantize the activation, then the packed product.
63
+ Trailing batch dimensions are preserved."""
64
+ shape = x.shape[:-1]
65
+ q, s = quantize_activation(x)
66
+ out = binary_gemm(q, s, wq, wscale, bias, group_size)
67
+ return out.reshape(*shape, out.shape[-1])
68
+
69
+
70
+ class BinaryLinear(torch.nn.Module):
71
+ """Drop-in for a binary-weight ``nn.Linear``. Holds packed weights and their
72
+ group scales; nothing is stored at higher precision."""
73
+
74
+ def __init__(self, in_features: int, out_features: int, bias: bool = False,
75
+ group_size: int = GROUP, device=None):
76
+ super().__init__()
77
+ assert in_features % 32 == 0, "in_features must be a multiple of 32"
78
+ assert in_features % group_size == 0, "in_features must be a multiple of group_size"
79
+ self.in_features = in_features
80
+ self.out_features = out_features
81
+ self.group_size = group_size
82
+ self.register_buffer(
83
+ "wq", torch.zeros(out_features, in_features // 32, dtype=torch.int32,
84
+ device=device))
85
+ self.register_buffer(
86
+ "wscale", torch.ones(out_features, in_features // group_size,
87
+ dtype=torch.float16, device=device))
88
+ self.bias = torch.nn.Parameter(
89
+ torch.zeros(out_features, device=device)) if bias else None
90
+
91
+ @classmethod
92
+ def from_dense(cls, lin: torch.nn.Linear, group_size: int = GROUP) -> "BinaryLinear":
93
+ """Binarize an existing linear by sign, with the group scale set to the
94
+ group's mean absolute weight, which is the scale that minimizes squared
95
+ error for a sign-quantized group."""
96
+ W = lin.weight.data
97
+ N, K = W.shape
98
+ m = cls(K, N, bias=lin.bias is not None, group_size=group_size,
99
+ device=W.device)
100
+ signs = torch.where(W >= 0, 1, -1).to(torch.int8)
101
+ m.wq.copy_(pack_weights(signs))
102
+ m.wscale.copy_(W.reshape(N, K // group_size, group_size).abs().mean(-1)
103
+ .to(torch.float16))
104
+ if lin.bias is not None:
105
+ m.bias.data.copy_(lin.bias.data)
106
+ return m
107
+
108
+ def forward(self, x: torch.Tensor) -> torch.Tensor:
109
+ return binary_linear(x, self.wq, self.wscale, self.bias, self.group_size)
110
+
111
+ def extra_repr(self) -> str:
112
+ bits = 1 + 16 / self.group_size
113
+ return (f"in_features={self.in_features}, out_features={self.out_features}, "
114
+ f"group_size={self.group_size}, effective_bits={bits:.3f}")
build/torch211-cxx11-cu128-x86_64-linux/_binary_gemm_cuda_31ce78e.abi3.so ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:1d94c2e858f5285c82375e55ffeabe003db5b49f3c0f27bc178aff911554010b
3
+ size 655336
build/torch211-cxx11-cu128-x86_64-linux/_ops.py ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ import torch
2
+ from . import _binary_gemm_cuda_31ce78e
3
+ ops = torch.ops._binary_gemm_cuda_31ce78e
4
+
5
+ def add_op_namespace_prefix(op_name: str):
6
+ """
7
+ Prefix op by namespace.
8
+ """
9
+ return f"_binary_gemm_cuda_31ce78e::{op_name}"
build/torch211-cxx11-cu128-x86_64-linux/binary_gemm/__init__.py ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import ctypes
2
+ import importlib.util
3
+ import sys
4
+ from pathlib import Path
5
+ from types import ModuleType
6
+
7
+
8
+ def _import_from_path(file_path: Path) -> ModuleType:
9
+ # We cannot use the module name as-is, after adding it to `sys.modules`,
10
+ # it would also be used for other imports. So, we make a module name that
11
+ # depends on the path for it to be unique using the hex-encoded hash of
12
+ # the path.
13
+ path_hash = "{:x}".format(ctypes.c_size_t(hash(file_path.absolute())).value)
14
+ module_name = path_hash
15
+ spec = importlib.util.spec_from_file_location(module_name, file_path)
16
+ if spec is None:
17
+ raise ImportError(f"Cannot load spec for {module_name} from {file_path}")
18
+ module = importlib.util.module_from_spec(spec)
19
+ if module is None:
20
+ raise ImportError(f"Cannot load module {module_name} from spec")
21
+ sys.modules[module_name] = module
22
+ spec.loader.exec_module(module) # type: ignore
23
+ return module
24
+
25
+
26
+ globals().update(vars(_import_from_path(Path(__file__).parent.parent / "__init__.py")))
build/torch211-cxx11-cu128-x86_64-linux/metadata.json ADDED
@@ -0,0 +1,38 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "binary-gemm",
3
+ "id": "_binary_gemm_cuda_31ce78e",
4
+ "version": 1,
5
+ "license": "Apache-2.0",
6
+ "python-depends": [],
7
+ "backend": {
8
+ "type": "cuda",
9
+ "archs": [
10
+ "10.0",
11
+ "12.0",
12
+ "8.0",
13
+ "8.6",
14
+ "8.9",
15
+ "9.0"
16
+ ]
17
+ },
18
+ "digest": {
19
+ "algorithm": "sha256",
20
+ "files": {
21
+ "__init__.py": "fwn5WUojHrxLQwNl70+IAx7FZfHJQI9O+Zp5h4F+n7Y=",
22
+ "_binary_gemm_cuda_31ce78e.abi3.so": "HZTC6Fj1KFyCN15V/+q+AD21tJ88Dye8F4r/kRVUAQs=",
23
+ "_ops.py": "cGdYjoXrblpZs8DIqLlPArXWztTZ+wWrveEjvYq+5/0=",
24
+ "binary_gemm/__init__.py": "DFYPlrhXwYjEqCl/8n0SmWGZV8NFml5DPhMjKfv98GY="
25
+ }
26
+ },
27
+ "provenance": {
28
+ "kernel-builder": {
29
+ "version": "0.17.0-dev0",
30
+ "sha": "19aaa6421e674e9fecc352bbae6eab81d19a6bf4",
31
+ "dirty": false
32
+ },
33
+ "kernel": {
34
+ "sha": "31ce78ecfe5b53cd413fd76785b351410c1f610a",
35
+ "dirty": false
36
+ }
37
+ }
38
+ }
build/torch211-cxx11-cu130-x86_64-linux/__init__.py ADDED
@@ -0,0 +1,114 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """binary-gemm: W1A8 matrix products for binary-weight language models.
2
+
3
+ Each weight is one bit meaning +1 or -1, with one fp16 scale per group of G
4
+ weights: at G = 128 that is 1.125 effective bits, against 2 bits for a ternary
5
+ layer and 16 for bf16. Activations are quantized per token to int8.
6
+
7
+ Binary weights are not a special case of ternary. Writing the stored bit as
8
+ b = (w + 1) / 2, the inner product is 2 * sum_{b_i = 1} a_i - sum_i a_i, so the
9
+ weight is never materialized as a number. The kernel resolves four weights at a
10
+ time through a nibble table feeding __dp4a.
11
+
12
+ Ternary companions on the Hub: phanerozoic/bitnet-tc (CUDA),
13
+ phanerozoic/bitnet-cpu (CPU).
14
+ """
15
+ from typing import Optional, Tuple
16
+
17
+ import torch
18
+
19
+ from ._ops import ops
20
+
21
+ __all__ = [
22
+ "pack_weights", "unpack_weights", "quantize_activation", "binary_gemm",
23
+ "binary_linear", "BinaryLinear",
24
+ ]
25
+
26
+ GROUP = 128
27
+
28
+
29
+ def pack_weights(w: torch.Tensor) -> torch.Tensor:
30
+ """Pack a ``{-1, +1}`` int8 ``[N, K]`` matrix to ``[N, K//32]`` int32.
31
+
32
+ Bit j of word i holds weight ``32*i + j``: set means +1, clear means -1.
33
+ Zeros are treated as -1, so a ternary tensor will not round-trip.
34
+ """
35
+ return ops.pack_weights(w.contiguous().to(torch.int8))
36
+
37
+
38
+ def unpack_weights(wq: torch.Tensor, K: int) -> torch.Tensor:
39
+ """Inverse of :func:`pack_weights`, for tests and for a reference path."""
40
+ bits = wq.to(torch.int32)
41
+ idx = torch.arange(32, device=wq.device, dtype=torch.int32)
42
+ out = ((bits.unsqueeze(-1) >> idx) & 1).to(torch.int8)
43
+ return (out.reshape(wq.shape[0], -1)[:, :K] * 2 - 1)
44
+
45
+
46
+ def quantize_activation(x: torch.Tensor) -> Tuple[torch.Tensor, torch.Tensor]:
47
+ """bf16 ``[..., K]`` -> (int8 ``[M, K]``, fp32 per-token scale ``[M]``)."""
48
+ q, s = ops.quantize_activation(x.contiguous().to(torch.bfloat16))
49
+ return q, s
50
+
51
+
52
+ def binary_gemm(act_q: torch.Tensor, act_scale: torch.Tensor, wq: torch.Tensor,
53
+ wscale: torch.Tensor, bias: Optional[torch.Tensor] = None,
54
+ group_size: int = GROUP) -> torch.Tensor:
55
+ """int8 activations times packed binary weights -> bf16 ``[M, N]``."""
56
+ return ops.binary_gemm(act_q, act_scale, wq, wscale, bias, group_size)
57
+
58
+
59
+ def binary_linear(x: torch.Tensor, wq: torch.Tensor, wscale: torch.Tensor,
60
+ bias: Optional[torch.Tensor] = None,
61
+ group_size: int = GROUP) -> torch.Tensor:
62
+ """One-shot forward: quantize the activation, then the packed product.
63
+ Trailing batch dimensions are preserved."""
64
+ shape = x.shape[:-1]
65
+ q, s = quantize_activation(x)
66
+ out = binary_gemm(q, s, wq, wscale, bias, group_size)
67
+ return out.reshape(*shape, out.shape[-1])
68
+
69
+
70
+ class BinaryLinear(torch.nn.Module):
71
+ """Drop-in for a binary-weight ``nn.Linear``. Holds packed weights and their
72
+ group scales; nothing is stored at higher precision."""
73
+
74
+ def __init__(self, in_features: int, out_features: int, bias: bool = False,
75
+ group_size: int = GROUP, device=None):
76
+ super().__init__()
77
+ assert in_features % 32 == 0, "in_features must be a multiple of 32"
78
+ assert in_features % group_size == 0, "in_features must be a multiple of group_size"
79
+ self.in_features = in_features
80
+ self.out_features = out_features
81
+ self.group_size = group_size
82
+ self.register_buffer(
83
+ "wq", torch.zeros(out_features, in_features // 32, dtype=torch.int32,
84
+ device=device))
85
+ self.register_buffer(
86
+ "wscale", torch.ones(out_features, in_features // group_size,
87
+ dtype=torch.float16, device=device))
88
+ self.bias = torch.nn.Parameter(
89
+ torch.zeros(out_features, device=device)) if bias else None
90
+
91
+ @classmethod
92
+ def from_dense(cls, lin: torch.nn.Linear, group_size: int = GROUP) -> "BinaryLinear":
93
+ """Binarize an existing linear by sign, with the group scale set to the
94
+ group's mean absolute weight, which is the scale that minimizes squared
95
+ error for a sign-quantized group."""
96
+ W = lin.weight.data
97
+ N, K = W.shape
98
+ m = cls(K, N, bias=lin.bias is not None, group_size=group_size,
99
+ device=W.device)
100
+ signs = torch.where(W >= 0, 1, -1).to(torch.int8)
101
+ m.wq.copy_(pack_weights(signs))
102
+ m.wscale.copy_(W.reshape(N, K // group_size, group_size).abs().mean(-1)
103
+ .to(torch.float16))
104
+ if lin.bias is not None:
105
+ m.bias.data.copy_(lin.bias.data)
106
+ return m
107
+
108
+ def forward(self, x: torch.Tensor) -> torch.Tensor:
109
+ return binary_linear(x, self.wq, self.wscale, self.bias, self.group_size)
110
+
111
+ def extra_repr(self) -> str:
112
+ bits = 1 + 16 / self.group_size
113
+ return (f"in_features={self.in_features}, out_features={self.out_features}, "
114
+ f"group_size={self.group_size}, effective_bits={bits:.3f}")
build/torch211-cxx11-cu130-x86_64-linux/_binary_gemm_cuda_31ce78e.abi3.so ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:73836d8e9c2e4fd31428ec170ee045ac2488cddf0a4dcebb2abe7c2a22fbf7f6
3
+ size 682200
build/torch211-cxx11-cu130-x86_64-linux/_ops.py ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ import torch
2
+ from . import _binary_gemm_cuda_31ce78e
3
+ ops = torch.ops._binary_gemm_cuda_31ce78e
4
+
5
+ def add_op_namespace_prefix(op_name: str):
6
+ """
7
+ Prefix op by namespace.
8
+ """
9
+ return f"_binary_gemm_cuda_31ce78e::{op_name}"
build/torch211-cxx11-cu130-x86_64-linux/binary_gemm/__init__.py ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import ctypes
2
+ import importlib.util
3
+ import sys
4
+ from pathlib import Path
5
+ from types import ModuleType
6
+
7
+
8
+ def _import_from_path(file_path: Path) -> ModuleType:
9
+ # We cannot use the module name as-is, after adding it to `sys.modules`,
10
+ # it would also be used for other imports. So, we make a module name that
11
+ # depends on the path for it to be unique using the hex-encoded hash of
12
+ # the path.
13
+ path_hash = "{:x}".format(ctypes.c_size_t(hash(file_path.absolute())).value)
14
+ module_name = path_hash
15
+ spec = importlib.util.spec_from_file_location(module_name, file_path)
16
+ if spec is None:
17
+ raise ImportError(f"Cannot load spec for {module_name} from {file_path}")
18
+ module = importlib.util.module_from_spec(spec)
19
+ if module is None:
20
+ raise ImportError(f"Cannot load module {module_name} from spec")
21
+ sys.modules[module_name] = module
22
+ spec.loader.exec_module(module) # type: ignore
23
+ return module
24
+
25
+
26
+ globals().update(vars(_import_from_path(Path(__file__).parent.parent / "__init__.py")))
build/torch211-cxx11-cu130-x86_64-linux/metadata.json ADDED
@@ -0,0 +1,38 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "binary-gemm",
3
+ "id": "_binary_gemm_cuda_31ce78e",
4
+ "version": 1,
5
+ "license": "Apache-2.0",
6
+ "python-depends": [],
7
+ "backend": {
8
+ "type": "cuda",
9
+ "archs": [
10
+ "10.0",
11
+ "12.0",
12
+ "8.0",
13
+ "8.6",
14
+ "8.9",
15
+ "9.0"
16
+ ]
17
+ },
18
+ "digest": {
19
+ "algorithm": "sha256",
20
+ "files": {
21
+ "__init__.py": "fwn5WUojHrxLQwNl70+IAx7FZfHJQI9O+Zp5h4F+n7Y=",
22
+ "_binary_gemm_cuda_31ce78e.abi3.so": "c4NtjpwuT9MUKOwXDuBFrCSIzd8KTc67Kr58KiL79/Y=",
23
+ "_ops.py": "cGdYjoXrblpZs8DIqLlPArXWztTZ+wWrveEjvYq+5/0=",
24
+ "binary_gemm/__init__.py": "DFYPlrhXwYjEqCl/8n0SmWGZV8NFml5DPhMjKfv98GY="
25
+ }
26
+ },
27
+ "provenance": {
28
+ "kernel-builder": {
29
+ "version": "0.17.0-dev0",
30
+ "sha": "19aaa6421e674e9fecc352bbae6eab81d19a6bf4",
31
+ "dirty": false
32
+ },
33
+ "kernel": {
34
+ "sha": "31ce78ecfe5b53cd413fd76785b351410c1f610a",
35
+ "dirty": false
36
+ }
37
+ }
38
+ }
build/torch212-cxx11-cu126-x86_64-linux/__init__.py ADDED
@@ -0,0 +1,114 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """binary-gemm: W1A8 matrix products for binary-weight language models.
2
+
3
+ Each weight is one bit meaning +1 or -1, with one fp16 scale per group of G
4
+ weights: at G = 128 that is 1.125 effective bits, against 2 bits for a ternary
5
+ layer and 16 for bf16. Activations are quantized per token to int8.
6
+
7
+ Binary weights are not a special case of ternary. Writing the stored bit as
8
+ b = (w + 1) / 2, the inner product is 2 * sum_{b_i = 1} a_i - sum_i a_i, so the
9
+ weight is never materialized as a number. The kernel resolves four weights at a
10
+ time through a nibble table feeding __dp4a.
11
+
12
+ Ternary companions on the Hub: phanerozoic/bitnet-tc (CUDA),
13
+ phanerozoic/bitnet-cpu (CPU).
14
+ """
15
+ from typing import Optional, Tuple
16
+
17
+ import torch
18
+
19
+ from ._ops import ops
20
+
21
+ __all__ = [
22
+ "pack_weights", "unpack_weights", "quantize_activation", "binary_gemm",
23
+ "binary_linear", "BinaryLinear",
24
+ ]
25
+
26
+ GROUP = 128
27
+
28
+
29
+ def pack_weights(w: torch.Tensor) -> torch.Tensor:
30
+ """Pack a ``{-1, +1}`` int8 ``[N, K]`` matrix to ``[N, K//32]`` int32.
31
+
32
+ Bit j of word i holds weight ``32*i + j``: set means +1, clear means -1.
33
+ Zeros are treated as -1, so a ternary tensor will not round-trip.
34
+ """
35
+ return ops.pack_weights(w.contiguous().to(torch.int8))
36
+
37
+
38
+ def unpack_weights(wq: torch.Tensor, K: int) -> torch.Tensor:
39
+ """Inverse of :func:`pack_weights`, for tests and for a reference path."""
40
+ bits = wq.to(torch.int32)
41
+ idx = torch.arange(32, device=wq.device, dtype=torch.int32)
42
+ out = ((bits.unsqueeze(-1) >> idx) & 1).to(torch.int8)
43
+ return (out.reshape(wq.shape[0], -1)[:, :K] * 2 - 1)
44
+
45
+
46
+ def quantize_activation(x: torch.Tensor) -> Tuple[torch.Tensor, torch.Tensor]:
47
+ """bf16 ``[..., K]`` -> (int8 ``[M, K]``, fp32 per-token scale ``[M]``)."""
48
+ q, s = ops.quantize_activation(x.contiguous().to(torch.bfloat16))
49
+ return q, s
50
+
51
+
52
+ def binary_gemm(act_q: torch.Tensor, act_scale: torch.Tensor, wq: torch.Tensor,
53
+ wscale: torch.Tensor, bias: Optional[torch.Tensor] = None,
54
+ group_size: int = GROUP) -> torch.Tensor:
55
+ """int8 activations times packed binary weights -> bf16 ``[M, N]``."""
56
+ return ops.binary_gemm(act_q, act_scale, wq, wscale, bias, group_size)
57
+
58
+
59
+ def binary_linear(x: torch.Tensor, wq: torch.Tensor, wscale: torch.Tensor,
60
+ bias: Optional[torch.Tensor] = None,
61
+ group_size: int = GROUP) -> torch.Tensor:
62
+ """One-shot forward: quantize the activation, then the packed product.
63
+ Trailing batch dimensions are preserved."""
64
+ shape = x.shape[:-1]
65
+ q, s = quantize_activation(x)
66
+ out = binary_gemm(q, s, wq, wscale, bias, group_size)
67
+ return out.reshape(*shape, out.shape[-1])
68
+
69
+
70
+ class BinaryLinear(torch.nn.Module):
71
+ """Drop-in for a binary-weight ``nn.Linear``. Holds packed weights and their
72
+ group scales; nothing is stored at higher precision."""
73
+
74
+ def __init__(self, in_features: int, out_features: int, bias: bool = False,
75
+ group_size: int = GROUP, device=None):
76
+ super().__init__()
77
+ assert in_features % 32 == 0, "in_features must be a multiple of 32"
78
+ assert in_features % group_size == 0, "in_features must be a multiple of group_size"
79
+ self.in_features = in_features
80
+ self.out_features = out_features
81
+ self.group_size = group_size
82
+ self.register_buffer(
83
+ "wq", torch.zeros(out_features, in_features // 32, dtype=torch.int32,
84
+ device=device))
85
+ self.register_buffer(
86
+ "wscale", torch.ones(out_features, in_features // group_size,
87
+ dtype=torch.float16, device=device))
88
+ self.bias = torch.nn.Parameter(
89
+ torch.zeros(out_features, device=device)) if bias else None
90
+
91
+ @classmethod
92
+ def from_dense(cls, lin: torch.nn.Linear, group_size: int = GROUP) -> "BinaryLinear":
93
+ """Binarize an existing linear by sign, with the group scale set to the
94
+ group's mean absolute weight, which is the scale that minimizes squared
95
+ error for a sign-quantized group."""
96
+ W = lin.weight.data
97
+ N, K = W.shape
98
+ m = cls(K, N, bias=lin.bias is not None, group_size=group_size,
99
+ device=W.device)
100
+ signs = torch.where(W >= 0, 1, -1).to(torch.int8)
101
+ m.wq.copy_(pack_weights(signs))
102
+ m.wscale.copy_(W.reshape(N, K // group_size, group_size).abs().mean(-1)
103
+ .to(torch.float16))
104
+ if lin.bias is not None:
105
+ m.bias.data.copy_(lin.bias.data)
106
+ return m
107
+
108
+ def forward(self, x: torch.Tensor) -> torch.Tensor:
109
+ return binary_linear(x, self.wq, self.wscale, self.bias, self.group_size)
110
+
111
+ def extra_repr(self) -> str:
112
+ bits = 1 + 16 / self.group_size
113
+ return (f"in_features={self.in_features}, out_features={self.out_features}, "
114
+ f"group_size={self.group_size}, effective_bits={bits:.3f}")
build/torch212-cxx11-cu126-x86_64-linux/_binary_gemm_cuda_31ce78e.abi3.so ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:cfc06dfc659837c4190ea30bb4b6296a6bb8513b9fc4e3376fe649f79b6dd91a
3
+ size 439624
build/torch212-cxx11-cu126-x86_64-linux/_ops.py ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ import torch
2
+ from . import _binary_gemm_cuda_31ce78e
3
+ ops = torch.ops._binary_gemm_cuda_31ce78e
4
+
5
+ def add_op_namespace_prefix(op_name: str):
6
+ """
7
+ Prefix op by namespace.
8
+ """
9
+ return f"_binary_gemm_cuda_31ce78e::{op_name}"
build/torch212-cxx11-cu126-x86_64-linux/binary_gemm/__init__.py ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import ctypes
2
+ import importlib.util
3
+ import sys
4
+ from pathlib import Path
5
+ from types import ModuleType
6
+
7
+
8
+ def _import_from_path(file_path: Path) -> ModuleType:
9
+ # We cannot use the module name as-is, after adding it to `sys.modules`,
10
+ # it would also be used for other imports. So, we make a module name that
11
+ # depends on the path for it to be unique using the hex-encoded hash of
12
+ # the path.
13
+ path_hash = "{:x}".format(ctypes.c_size_t(hash(file_path.absolute())).value)
14
+ module_name = path_hash
15
+ spec = importlib.util.spec_from_file_location(module_name, file_path)
16
+ if spec is None:
17
+ raise ImportError(f"Cannot load spec for {module_name} from {file_path}")
18
+ module = importlib.util.module_from_spec(spec)
19
+ if module is None:
20
+ raise ImportError(f"Cannot load module {module_name} from spec")
21
+ sys.modules[module_name] = module
22
+ spec.loader.exec_module(module) # type: ignore
23
+ return module
24
+
25
+
26
+ globals().update(vars(_import_from_path(Path(__file__).parent.parent / "__init__.py")))
build/torch212-cxx11-cu126-x86_64-linux/metadata.json ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "binary-gemm",
3
+ "id": "_binary_gemm_cuda_31ce78e",
4
+ "version": 1,
5
+ "license": "Apache-2.0",
6
+ "python-depends": [],
7
+ "backend": {
8
+ "type": "cuda",
9
+ "archs": [
10
+ "8.0",
11
+ "8.6",
12
+ "8.9",
13
+ "9.0"
14
+ ]
15
+ },
16
+ "digest": {
17
+ "algorithm": "sha256",
18
+ "files": {
19
+ "__init__.py": "fwn5WUojHrxLQwNl70+IAx7FZfHJQI9O+Zp5h4F+n7Y=",
20
+ "_binary_gemm_cuda_31ce78e.abi3.so": "z8Bt/GWYN8QZDqMLtLYpamu4UTufxOM3b+ZJ95tt2Ro=",
21
+ "_ops.py": "cGdYjoXrblpZs8DIqLlPArXWztTZ+wWrveEjvYq+5/0=",
22
+ "binary_gemm/__init__.py": "DFYPlrhXwYjEqCl/8n0SmWGZV8NFml5DPhMjKfv98GY="
23
+ }
24
+ },
25
+ "provenance": {
26
+ "kernel-builder": {
27
+ "version": "0.17.0-dev0",
28
+ "sha": "19aaa6421e674e9fecc352bbae6eab81d19a6bf4",
29
+ "dirty": false
30
+ },
31
+ "kernel": {
32
+ "sha": "31ce78ecfe5b53cd413fd76785b351410c1f610a",
33
+ "dirty": false
34
+ }
35
+ }
36
+ }
build/torch212-cxx11-cu130-x86_64-linux/__init__.py ADDED
@@ -0,0 +1,114 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """binary-gemm: W1A8 matrix products for binary-weight language models.
2
+
3
+ Each weight is one bit meaning +1 or -1, with one fp16 scale per group of G
4
+ weights: at G = 128 that is 1.125 effective bits, against 2 bits for a ternary
5
+ layer and 16 for bf16. Activations are quantized per token to int8.
6
+
7
+ Binary weights are not a special case of ternary. Writing the stored bit as
8
+ b = (w + 1) / 2, the inner product is 2 * sum_{b_i = 1} a_i - sum_i a_i, so the
9
+ weight is never materialized as a number. The kernel resolves four weights at a
10
+ time through a nibble table feeding __dp4a.
11
+
12
+ Ternary companions on the Hub: phanerozoic/bitnet-tc (CUDA),
13
+ phanerozoic/bitnet-cpu (CPU).
14
+ """
15
+ from typing import Optional, Tuple
16
+
17
+ import torch
18
+
19
+ from ._ops import ops
20
+
21
+ __all__ = [
22
+ "pack_weights", "unpack_weights", "quantize_activation", "binary_gemm",
23
+ "binary_linear", "BinaryLinear",
24
+ ]
25
+
26
+ GROUP = 128
27
+
28
+
29
+ def pack_weights(w: torch.Tensor) -> torch.Tensor:
30
+ """Pack a ``{-1, +1}`` int8 ``[N, K]`` matrix to ``[N, K//32]`` int32.
31
+
32
+ Bit j of word i holds weight ``32*i + j``: set means +1, clear means -1.
33
+ Zeros are treated as -1, so a ternary tensor will not round-trip.
34
+ """
35
+ return ops.pack_weights(w.contiguous().to(torch.int8))
36
+
37
+
38
+ def unpack_weights(wq: torch.Tensor, K: int) -> torch.Tensor:
39
+ """Inverse of :func:`pack_weights`, for tests and for a reference path."""
40
+ bits = wq.to(torch.int32)
41
+ idx = torch.arange(32, device=wq.device, dtype=torch.int32)
42
+ out = ((bits.unsqueeze(-1) >> idx) & 1).to(torch.int8)
43
+ return (out.reshape(wq.shape[0], -1)[:, :K] * 2 - 1)
44
+
45
+
46
+ def quantize_activation(x: torch.Tensor) -> Tuple[torch.Tensor, torch.Tensor]:
47
+ """bf16 ``[..., K]`` -> (int8 ``[M, K]``, fp32 per-token scale ``[M]``)."""
48
+ q, s = ops.quantize_activation(x.contiguous().to(torch.bfloat16))
49
+ return q, s
50
+
51
+
52
+ def binary_gemm(act_q: torch.Tensor, act_scale: torch.Tensor, wq: torch.Tensor,
53
+ wscale: torch.Tensor, bias: Optional[torch.Tensor] = None,
54
+ group_size: int = GROUP) -> torch.Tensor:
55
+ """int8 activations times packed binary weights -> bf16 ``[M, N]``."""
56
+ return ops.binary_gemm(act_q, act_scale, wq, wscale, bias, group_size)
57
+
58
+
59
+ def binary_linear(x: torch.Tensor, wq: torch.Tensor, wscale: torch.Tensor,
60
+ bias: Optional[torch.Tensor] = None,
61
+ group_size: int = GROUP) -> torch.Tensor:
62
+ """One-shot forward: quantize the activation, then the packed product.
63
+ Trailing batch dimensions are preserved."""
64
+ shape = x.shape[:-1]
65
+ q, s = quantize_activation(x)
66
+ out = binary_gemm(q, s, wq, wscale, bias, group_size)
67
+ return out.reshape(*shape, out.shape[-1])
68
+
69
+
70
+ class BinaryLinear(torch.nn.Module):
71
+ """Drop-in for a binary-weight ``nn.Linear``. Holds packed weights and their
72
+ group scales; nothing is stored at higher precision."""
73
+
74
+ def __init__(self, in_features: int, out_features: int, bias: bool = False,
75
+ group_size: int = GROUP, device=None):
76
+ super().__init__()
77
+ assert in_features % 32 == 0, "in_features must be a multiple of 32"
78
+ assert in_features % group_size == 0, "in_features must be a multiple of group_size"
79
+ self.in_features = in_features
80
+ self.out_features = out_features
81
+ self.group_size = group_size
82
+ self.register_buffer(
83
+ "wq", torch.zeros(out_features, in_features // 32, dtype=torch.int32,
84
+ device=device))
85
+ self.register_buffer(
86
+ "wscale", torch.ones(out_features, in_features // group_size,
87
+ dtype=torch.float16, device=device))
88
+ self.bias = torch.nn.Parameter(
89
+ torch.zeros(out_features, device=device)) if bias else None
90
+
91
+ @classmethod
92
+ def from_dense(cls, lin: torch.nn.Linear, group_size: int = GROUP) -> "BinaryLinear":
93
+ """Binarize an existing linear by sign, with the group scale set to the
94
+ group's mean absolute weight, which is the scale that minimizes squared
95
+ error for a sign-quantized group."""
96
+ W = lin.weight.data
97
+ N, K = W.shape
98
+ m = cls(K, N, bias=lin.bias is not None, group_size=group_size,
99
+ device=W.device)
100
+ signs = torch.where(W >= 0, 1, -1).to(torch.int8)
101
+ m.wq.copy_(pack_weights(signs))
102
+ m.wscale.copy_(W.reshape(N, K // group_size, group_size).abs().mean(-1)
103
+ .to(torch.float16))
104
+ if lin.bias is not None:
105
+ m.bias.data.copy_(lin.bias.data)
106
+ return m
107
+
108
+ def forward(self, x: torch.Tensor) -> torch.Tensor:
109
+ return binary_linear(x, self.wq, self.wscale, self.bias, self.group_size)
110
+
111
+ def extra_repr(self) -> str:
112
+ bits = 1 + 16 / self.group_size
113
+ return (f"in_features={self.in_features}, out_features={self.out_features}, "
114
+ f"group_size={self.group_size}, effective_bits={bits:.3f}")
build/torch212-cxx11-cu130-x86_64-linux/_binary_gemm_cuda_31ce78e.abi3.so ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:d35024ab6c50dcf278e73b13bb43933e1136403d8b9a3b8f91c0564312895ebf
3
+ size 687272
build/torch212-cxx11-cu130-x86_64-linux/_ops.py ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ import torch
2
+ from . import _binary_gemm_cuda_31ce78e
3
+ ops = torch.ops._binary_gemm_cuda_31ce78e
4
+
5
+ def add_op_namespace_prefix(op_name: str):
6
+ """
7
+ Prefix op by namespace.
8
+ """
9
+ return f"_binary_gemm_cuda_31ce78e::{op_name}"
build/torch212-cxx11-cu130-x86_64-linux/binary_gemm/__init__.py ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import ctypes
2
+ import importlib.util
3
+ import sys
4
+ from pathlib import Path
5
+ from types import ModuleType
6
+
7
+
8
+ def _import_from_path(file_path: Path) -> ModuleType:
9
+ # We cannot use the module name as-is, after adding it to `sys.modules`,
10
+ # it would also be used for other imports. So, we make a module name that
11
+ # depends on the path for it to be unique using the hex-encoded hash of
12
+ # the path.
13
+ path_hash = "{:x}".format(ctypes.c_size_t(hash(file_path.absolute())).value)
14
+ module_name = path_hash
15
+ spec = importlib.util.spec_from_file_location(module_name, file_path)
16
+ if spec is None:
17
+ raise ImportError(f"Cannot load spec for {module_name} from {file_path}")
18
+ module = importlib.util.module_from_spec(spec)
19
+ if module is None:
20
+ raise ImportError(f"Cannot load module {module_name} from spec")
21
+ sys.modules[module_name] = module
22
+ spec.loader.exec_module(module) # type: ignore
23
+ return module
24
+
25
+
26
+ globals().update(vars(_import_from_path(Path(__file__).parent.parent / "__init__.py")))
build/torch212-cxx11-cu130-x86_64-linux/metadata.json ADDED
@@ -0,0 +1,38 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "binary-gemm",
3
+ "id": "_binary_gemm_cuda_31ce78e",
4
+ "version": 1,
5
+ "license": "Apache-2.0",
6
+ "python-depends": [],
7
+ "backend": {
8
+ "type": "cuda",
9
+ "archs": [
10
+ "10.0",
11
+ "12.0",
12
+ "8.0",
13
+ "8.6",
14
+ "8.9",
15
+ "9.0"
16
+ ]
17
+ },
18
+ "digest": {
19
+ "algorithm": "sha256",
20
+ "files": {
21
+ "__init__.py": "fwn5WUojHrxLQwNl70+IAx7FZfHJQI9O+Zp5h4F+n7Y=",
22
+ "_binary_gemm_cuda_31ce78e.abi3.so": "01Akq2xQ3PJ45zsTu0OTPhE2QD2LmjuPkcBWQxKJXr8=",
23
+ "_ops.py": "cGdYjoXrblpZs8DIqLlPArXWztTZ+wWrveEjvYq+5/0=",
24
+ "binary_gemm/__init__.py": "DFYPlrhXwYjEqCl/8n0SmWGZV8NFml5DPhMjKfv98GY="
25
+ }
26
+ },
27
+ "provenance": {
28
+ "kernel-builder": {
29
+ "version": "0.17.0-dev0",
30
+ "sha": "19aaa6421e674e9fecc352bbae6eab81d19a6bf4",
31
+ "dirty": false
32
+ },
33
+ "kernel": {
34
+ "sha": "31ce78ecfe5b53cd413fd76785b351410c1f610a",
35
+ "dirty": false
36
+ }
37
+ }
38
+ }
build/torch212-cxx11-cu132-x86_64-linux/__init__.py ADDED
@@ -0,0 +1,114 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """binary-gemm: W1A8 matrix products for binary-weight language models.
2
+
3
+ Each weight is one bit meaning +1 or -1, with one fp16 scale per group of G
4
+ weights: at G = 128 that is 1.125 effective bits, against 2 bits for a ternary
5
+ layer and 16 for bf16. Activations are quantized per token to int8.
6
+
7
+ Binary weights are not a special case of ternary. Writing the stored bit as
8
+ b = (w + 1) / 2, the inner product is 2 * sum_{b_i = 1} a_i - sum_i a_i, so the
9
+ weight is never materialized as a number. The kernel resolves four weights at a
10
+ time through a nibble table feeding __dp4a.
11
+
12
+ Ternary companions on the Hub: phanerozoic/bitnet-tc (CUDA),
13
+ phanerozoic/bitnet-cpu (CPU).
14
+ """
15
+ from typing import Optional, Tuple
16
+
17
+ import torch
18
+
19
+ from ._ops import ops
20
+
21
+ __all__ = [
22
+ "pack_weights", "unpack_weights", "quantize_activation", "binary_gemm",
23
+ "binary_linear", "BinaryLinear",
24
+ ]
25
+
26
+ GROUP = 128
27
+
28
+
29
+ def pack_weights(w: torch.Tensor) -> torch.Tensor:
30
+ """Pack a ``{-1, +1}`` int8 ``[N, K]`` matrix to ``[N, K//32]`` int32.
31
+
32
+ Bit j of word i holds weight ``32*i + j``: set means +1, clear means -1.
33
+ Zeros are treated as -1, so a ternary tensor will not round-trip.
34
+ """
35
+ return ops.pack_weights(w.contiguous().to(torch.int8))
36
+
37
+
38
+ def unpack_weights(wq: torch.Tensor, K: int) -> torch.Tensor:
39
+ """Inverse of :func:`pack_weights`, for tests and for a reference path."""
40
+ bits = wq.to(torch.int32)
41
+ idx = torch.arange(32, device=wq.device, dtype=torch.int32)
42
+ out = ((bits.unsqueeze(-1) >> idx) & 1).to(torch.int8)
43
+ return (out.reshape(wq.shape[0], -1)[:, :K] * 2 - 1)
44
+
45
+
46
+ def quantize_activation(x: torch.Tensor) -> Tuple[torch.Tensor, torch.Tensor]:
47
+ """bf16 ``[..., K]`` -> (int8 ``[M, K]``, fp32 per-token scale ``[M]``)."""
48
+ q, s = ops.quantize_activation(x.contiguous().to(torch.bfloat16))
49
+ return q, s
50
+
51
+
52
+ def binary_gemm(act_q: torch.Tensor, act_scale: torch.Tensor, wq: torch.Tensor,
53
+ wscale: torch.Tensor, bias: Optional[torch.Tensor] = None,
54
+ group_size: int = GROUP) -> torch.Tensor:
55
+ """int8 activations times packed binary weights -> bf16 ``[M, N]``."""
56
+ return ops.binary_gemm(act_q, act_scale, wq, wscale, bias, group_size)
57
+
58
+
59
+ def binary_linear(x: torch.Tensor, wq: torch.Tensor, wscale: torch.Tensor,
60
+ bias: Optional[torch.Tensor] = None,
61
+ group_size: int = GROUP) -> torch.Tensor:
62
+ """One-shot forward: quantize the activation, then the packed product.
63
+ Trailing batch dimensions are preserved."""
64
+ shape = x.shape[:-1]
65
+ q, s = quantize_activation(x)
66
+ out = binary_gemm(q, s, wq, wscale, bias, group_size)
67
+ return out.reshape(*shape, out.shape[-1])
68
+
69
+
70
+ class BinaryLinear(torch.nn.Module):
71
+ """Drop-in for a binary-weight ``nn.Linear``. Holds packed weights and their
72
+ group scales; nothing is stored at higher precision."""
73
+
74
+ def __init__(self, in_features: int, out_features: int, bias: bool = False,
75
+ group_size: int = GROUP, device=None):
76
+ super().__init__()
77
+ assert in_features % 32 == 0, "in_features must be a multiple of 32"
78
+ assert in_features % group_size == 0, "in_features must be a multiple of group_size"
79
+ self.in_features = in_features
80
+ self.out_features = out_features
81
+ self.group_size = group_size
82
+ self.register_buffer(
83
+ "wq", torch.zeros(out_features, in_features // 32, dtype=torch.int32,
84
+ device=device))
85
+ self.register_buffer(
86
+ "wscale", torch.ones(out_features, in_features // group_size,
87
+ dtype=torch.float16, device=device))
88
+ self.bias = torch.nn.Parameter(
89
+ torch.zeros(out_features, device=device)) if bias else None
90
+
91
+ @classmethod
92
+ def from_dense(cls, lin: torch.nn.Linear, group_size: int = GROUP) -> "BinaryLinear":
93
+ """Binarize an existing linear by sign, with the group scale set to the
94
+ group's mean absolute weight, which is the scale that minimizes squared
95
+ error for a sign-quantized group."""
96
+ W = lin.weight.data
97
+ N, K = W.shape
98
+ m = cls(K, N, bias=lin.bias is not None, group_size=group_size,
99
+ device=W.device)
100
+ signs = torch.where(W >= 0, 1, -1).to(torch.int8)
101
+ m.wq.copy_(pack_weights(signs))
102
+ m.wscale.copy_(W.reshape(N, K // group_size, group_size).abs().mean(-1)
103
+ .to(torch.float16))
104
+ if lin.bias is not None:
105
+ m.bias.data.copy_(lin.bias.data)
106
+ return m
107
+
108
+ def forward(self, x: torch.Tensor) -> torch.Tensor:
109
+ return binary_linear(x, self.wq, self.wscale, self.bias, self.group_size)
110
+
111
+ def extra_repr(self) -> str:
112
+ bits = 1 + 16 / self.group_size
113
+ return (f"in_features={self.in_features}, out_features={self.out_features}, "
114
+ f"group_size={self.group_size}, effective_bits={bits:.3f}")
build/torch212-cxx11-cu132-x86_64-linux/_binary_gemm_cuda_31ce78e.abi3.so ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:cd3c83131d08f6d8ea35a82715caa2f9c918be096e0ccc408189d22a7cd6818a
3
+ size 726192
build/torch212-cxx11-cu132-x86_64-linux/_ops.py ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ import torch
2
+ from . import _binary_gemm_cuda_31ce78e
3
+ ops = torch.ops._binary_gemm_cuda_31ce78e
4
+
5
+ def add_op_namespace_prefix(op_name: str):
6
+ """
7
+ Prefix op by namespace.
8
+ """
9
+ return f"_binary_gemm_cuda_31ce78e::{op_name}"
build/torch212-cxx11-cu132-x86_64-linux/binary_gemm/__init__.py ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import ctypes
2
+ import importlib.util
3
+ import sys
4
+ from pathlib import Path
5
+ from types import ModuleType
6
+
7
+
8
+ def _import_from_path(file_path: Path) -> ModuleType:
9
+ # We cannot use the module name as-is, after adding it to `sys.modules`,
10
+ # it would also be used for other imports. So, we make a module name that
11
+ # depends on the path for it to be unique using the hex-encoded hash of
12
+ # the path.
13
+ path_hash = "{:x}".format(ctypes.c_size_t(hash(file_path.absolute())).value)
14
+ module_name = path_hash
15
+ spec = importlib.util.spec_from_file_location(module_name, file_path)
16
+ if spec is None:
17
+ raise ImportError(f"Cannot load spec for {module_name} from {file_path}")
18
+ module = importlib.util.module_from_spec(spec)
19
+ if module is None:
20
+ raise ImportError(f"Cannot load module {module_name} from spec")
21
+ sys.modules[module_name] = module
22
+ spec.loader.exec_module(module) # type: ignore
23
+ return module
24
+
25
+
26
+ globals().update(vars(_import_from_path(Path(__file__).parent.parent / "__init__.py")))
build/torch212-cxx11-cu132-x86_64-linux/metadata.json ADDED
@@ -0,0 +1,38 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "binary-gemm",
3
+ "id": "_binary_gemm_cuda_31ce78e",
4
+ "version": 1,
5
+ "license": "Apache-2.0",
6
+ "python-depends": [],
7
+ "backend": {
8
+ "type": "cuda",
9
+ "archs": [
10
+ "10.0",
11
+ "12.0",
12
+ "8.0",
13
+ "8.6",
14
+ "8.9",
15
+ "9.0"
16
+ ]
17
+ },
18
+ "digest": {
19
+ "algorithm": "sha256",
20
+ "files": {
21
+ "__init__.py": "fwn5WUojHrxLQwNl70+IAx7FZfHJQI9O+Zp5h4F+n7Y=",
22
+ "_binary_gemm_cuda_31ce78e.abi3.so": "zTyDEx0I9tjqNagnFcqi+ckYvgluDMxAgYnSKnzWgYo=",
23
+ "_ops.py": "cGdYjoXrblpZs8DIqLlPArXWztTZ+wWrveEjvYq+5/0=",
24
+ "binary_gemm/__init__.py": "DFYPlrhXwYjEqCl/8n0SmWGZV8NFml5DPhMjKfv98GY="
25
+ }
26
+ },
27
+ "provenance": {
28
+ "kernel-builder": {
29
+ "version": "0.17.0-dev0",
30
+ "sha": "19aaa6421e674e9fecc352bbae6eab81d19a6bf4",
31
+ "dirty": false
32
+ },
33
+ "kernel": {
34
+ "sha": "31ce78ecfe5b53cd413fd76785b351410c1f610a",
35
+ "dirty": false
36
+ }
37
+ }
38
+ }
build/torch213-cxx11-cu126-x86_64-linux/__init__.py ADDED
@@ -0,0 +1,114 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """binary-gemm: W1A8 matrix products for binary-weight language models.
2
+
3
+ Each weight is one bit meaning +1 or -1, with one fp16 scale per group of G
4
+ weights: at G = 128 that is 1.125 effective bits, against 2 bits for a ternary
5
+ layer and 16 for bf16. Activations are quantized per token to int8.
6
+
7
+ Binary weights are not a special case of ternary. Writing the stored bit as
8
+ b = (w + 1) / 2, the inner product is 2 * sum_{b_i = 1} a_i - sum_i a_i, so the
9
+ weight is never materialized as a number. The kernel resolves four weights at a
10
+ time through a nibble table feeding __dp4a.
11
+
12
+ Ternary companions on the Hub: phanerozoic/bitnet-tc (CUDA),
13
+ phanerozoic/bitnet-cpu (CPU).
14
+ """
15
+ from typing import Optional, Tuple
16
+
17
+ import torch
18
+
19
+ from ._ops import ops
20
+
21
+ __all__ = [
22
+ "pack_weights", "unpack_weights", "quantize_activation", "binary_gemm",
23
+ "binary_linear", "BinaryLinear",
24
+ ]
25
+
26
+ GROUP = 128
27
+
28
+
29
+ def pack_weights(w: torch.Tensor) -> torch.Tensor:
30
+ """Pack a ``{-1, +1}`` int8 ``[N, K]`` matrix to ``[N, K//32]`` int32.
31
+
32
+ Bit j of word i holds weight ``32*i + j``: set means +1, clear means -1.
33
+ Zeros are treated as -1, so a ternary tensor will not round-trip.
34
+ """
35
+ return ops.pack_weights(w.contiguous().to(torch.int8))
36
+
37
+
38
+ def unpack_weights(wq: torch.Tensor, K: int) -> torch.Tensor:
39
+ """Inverse of :func:`pack_weights`, for tests and for a reference path."""
40
+ bits = wq.to(torch.int32)
41
+ idx = torch.arange(32, device=wq.device, dtype=torch.int32)
42
+ out = ((bits.unsqueeze(-1) >> idx) & 1).to(torch.int8)
43
+ return (out.reshape(wq.shape[0], -1)[:, :K] * 2 - 1)
44
+
45
+
46
+ def quantize_activation(x: torch.Tensor) -> Tuple[torch.Tensor, torch.Tensor]:
47
+ """bf16 ``[..., K]`` -> (int8 ``[M, K]``, fp32 per-token scale ``[M]``)."""
48
+ q, s = ops.quantize_activation(x.contiguous().to(torch.bfloat16))
49
+ return q, s
50
+
51
+
52
+ def binary_gemm(act_q: torch.Tensor, act_scale: torch.Tensor, wq: torch.Tensor,
53
+ wscale: torch.Tensor, bias: Optional[torch.Tensor] = None,
54
+ group_size: int = GROUP) -> torch.Tensor:
55
+ """int8 activations times packed binary weights -> bf16 ``[M, N]``."""
56
+ return ops.binary_gemm(act_q, act_scale, wq, wscale, bias, group_size)
57
+
58
+
59
+ def binary_linear(x: torch.Tensor, wq: torch.Tensor, wscale: torch.Tensor,
60
+ bias: Optional[torch.Tensor] = None,
61
+ group_size: int = GROUP) -> torch.Tensor:
62
+ """One-shot forward: quantize the activation, then the packed product.
63
+ Trailing batch dimensions are preserved."""
64
+ shape = x.shape[:-1]
65
+ q, s = quantize_activation(x)
66
+ out = binary_gemm(q, s, wq, wscale, bias, group_size)
67
+ return out.reshape(*shape, out.shape[-1])
68
+
69
+
70
+ class BinaryLinear(torch.nn.Module):
71
+ """Drop-in for a binary-weight ``nn.Linear``. Holds packed weights and their
72
+ group scales; nothing is stored at higher precision."""
73
+
74
+ def __init__(self, in_features: int, out_features: int, bias: bool = False,
75
+ group_size: int = GROUP, device=None):
76
+ super().__init__()
77
+ assert in_features % 32 == 0, "in_features must be a multiple of 32"
78
+ assert in_features % group_size == 0, "in_features must be a multiple of group_size"
79
+ self.in_features = in_features
80
+ self.out_features = out_features
81
+ self.group_size = group_size
82
+ self.register_buffer(
83
+ "wq", torch.zeros(out_features, in_features // 32, dtype=torch.int32,
84
+ device=device))
85
+ self.register_buffer(
86
+ "wscale", torch.ones(out_features, in_features // group_size,
87
+ dtype=torch.float16, device=device))
88
+ self.bias = torch.nn.Parameter(
89
+ torch.zeros(out_features, device=device)) if bias else None
90
+
91
+ @classmethod
92
+ def from_dense(cls, lin: torch.nn.Linear, group_size: int = GROUP) -> "BinaryLinear":
93
+ """Binarize an existing linear by sign, with the group scale set to the
94
+ group's mean absolute weight, which is the scale that minimizes squared
95
+ error for a sign-quantized group."""
96
+ W = lin.weight.data
97
+ N, K = W.shape
98
+ m = cls(K, N, bias=lin.bias is not None, group_size=group_size,
99
+ device=W.device)
100
+ signs = torch.where(W >= 0, 1, -1).to(torch.int8)
101
+ m.wq.copy_(pack_weights(signs))
102
+ m.wscale.copy_(W.reshape(N, K // group_size, group_size).abs().mean(-1)
103
+ .to(torch.float16))
104
+ if lin.bias is not None:
105
+ m.bias.data.copy_(lin.bias.data)
106
+ return m
107
+
108
+ def forward(self, x: torch.Tensor) -> torch.Tensor:
109
+ return binary_linear(x, self.wq, self.wscale, self.bias, self.group_size)
110
+
111
+ def extra_repr(self) -> str:
112
+ bits = 1 + 16 / self.group_size
113
+ return (f"in_features={self.in_features}, out_features={self.out_features}, "
114
+ f"group_size={self.group_size}, effective_bits={bits:.3f}")
build/torch213-cxx11-cu126-x86_64-linux/_binary_gemm_cuda_31ce78e.abi3.so ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:65b2374bfd12bf73d357aa8b65328b19085187c6b1ca37d1dfedc8f9d2b86a4f
3
+ size 439464
build/torch213-cxx11-cu126-x86_64-linux/_ops.py ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ import torch
2
+ from . import _binary_gemm_cuda_31ce78e
3
+ ops = torch.ops._binary_gemm_cuda_31ce78e
4
+
5
+ def add_op_namespace_prefix(op_name: str):
6
+ """
7
+ Prefix op by namespace.
8
+ """
9
+ return f"_binary_gemm_cuda_31ce78e::{op_name}"
build/torch213-cxx11-cu126-x86_64-linux/binary_gemm/__init__.py ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import ctypes
2
+ import importlib.util
3
+ import sys
4
+ from pathlib import Path
5
+ from types import ModuleType
6
+
7
+
8
+ def _import_from_path(file_path: Path) -> ModuleType:
9
+ # We cannot use the module name as-is, after adding it to `sys.modules`,
10
+ # it would also be used for other imports. So, we make a module name that
11
+ # depends on the path for it to be unique using the hex-encoded hash of
12
+ # the path.
13
+ path_hash = "{:x}".format(ctypes.c_size_t(hash(file_path.absolute())).value)
14
+ module_name = path_hash
15
+ spec = importlib.util.spec_from_file_location(module_name, file_path)
16
+ if spec is None:
17
+ raise ImportError(f"Cannot load spec for {module_name} from {file_path}")
18
+ module = importlib.util.module_from_spec(spec)
19
+ if module is None:
20
+ raise ImportError(f"Cannot load module {module_name} from spec")
21
+ sys.modules[module_name] = module
22
+ spec.loader.exec_module(module) # type: ignore
23
+ return module
24
+
25
+
26
+ globals().update(vars(_import_from_path(Path(__file__).parent.parent / "__init__.py")))
build/torch213-cxx11-cu126-x86_64-linux/metadata.json ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "binary-gemm",
3
+ "id": "_binary_gemm_cuda_31ce78e",
4
+ "version": 1,
5
+ "license": "Apache-2.0",
6
+ "python-depends": [],
7
+ "backend": {
8
+ "type": "cuda",
9
+ "archs": [
10
+ "8.0",
11
+ "8.6",
12
+ "8.9",
13
+ "9.0"
14
+ ]
15
+ },
16
+ "digest": {
17
+ "algorithm": "sha256",
18
+ "files": {
19
+ "__init__.py": "fwn5WUojHrxLQwNl70+IAx7FZfHJQI9O+Zp5h4F+n7Y=",
20
+ "_binary_gemm_cuda_31ce78e.abi3.so": "ZbI3S/0Sv3PTV6qLZTKLGQhRh8axyjfR3+3I+dK4ak8=",
21
+ "_ops.py": "cGdYjoXrblpZs8DIqLlPArXWztTZ+wWrveEjvYq+5/0=",
22
+ "binary_gemm/__init__.py": "DFYPlrhXwYjEqCl/8n0SmWGZV8NFml5DPhMjKfv98GY="
23
+ }
24
+ },
25
+ "provenance": {
26
+ "kernel-builder": {
27
+ "version": "0.17.0-dev0",
28
+ "sha": "19aaa6421e674e9fecc352bbae6eab81d19a6bf4",
29
+ "dirty": false
30
+ },
31
+ "kernel": {
32
+ "sha": "31ce78ecfe5b53cd413fd76785b351410c1f610a",
33
+ "dirty": false
34
+ }
35
+ }
36
+ }
build/torch213-cxx11-cu130-x86_64-linux/__init__.py ADDED
@@ -0,0 +1,114 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """binary-gemm: W1A8 matrix products for binary-weight language models.
2
+
3
+ Each weight is one bit meaning +1 or -1, with one fp16 scale per group of G
4
+ weights: at G = 128 that is 1.125 effective bits, against 2 bits for a ternary
5
+ layer and 16 for bf16. Activations are quantized per token to int8.
6
+
7
+ Binary weights are not a special case of ternary. Writing the stored bit as
8
+ b = (w + 1) / 2, the inner product is 2 * sum_{b_i = 1} a_i - sum_i a_i, so the
9
+ weight is never materialized as a number. The kernel resolves four weights at a
10
+ time through a nibble table feeding __dp4a.
11
+
12
+ Ternary companions on the Hub: phanerozoic/bitnet-tc (CUDA),
13
+ phanerozoic/bitnet-cpu (CPU).
14
+ """
15
+ from typing import Optional, Tuple
16
+
17
+ import torch
18
+
19
+ from ._ops import ops
20
+
21
+ __all__ = [
22
+ "pack_weights", "unpack_weights", "quantize_activation", "binary_gemm",
23
+ "binary_linear", "BinaryLinear",
24
+ ]
25
+
26
+ GROUP = 128
27
+
28
+
29
+ def pack_weights(w: torch.Tensor) -> torch.Tensor:
30
+ """Pack a ``{-1, +1}`` int8 ``[N, K]`` matrix to ``[N, K//32]`` int32.
31
+
32
+ Bit j of word i holds weight ``32*i + j``: set means +1, clear means -1.
33
+ Zeros are treated as -1, so a ternary tensor will not round-trip.
34
+ """
35
+ return ops.pack_weights(w.contiguous().to(torch.int8))
36
+
37
+
38
+ def unpack_weights(wq: torch.Tensor, K: int) -> torch.Tensor:
39
+ """Inverse of :func:`pack_weights`, for tests and for a reference path."""
40
+ bits = wq.to(torch.int32)
41
+ idx = torch.arange(32, device=wq.device, dtype=torch.int32)
42
+ out = ((bits.unsqueeze(-1) >> idx) & 1).to(torch.int8)
43
+ return (out.reshape(wq.shape[0], -1)[:, :K] * 2 - 1)
44
+
45
+
46
+ def quantize_activation(x: torch.Tensor) -> Tuple[torch.Tensor, torch.Tensor]:
47
+ """bf16 ``[..., K]`` -> (int8 ``[M, K]``, fp32 per-token scale ``[M]``)."""
48
+ q, s = ops.quantize_activation(x.contiguous().to(torch.bfloat16))
49
+ return q, s
50
+
51
+
52
+ def binary_gemm(act_q: torch.Tensor, act_scale: torch.Tensor, wq: torch.Tensor,
53
+ wscale: torch.Tensor, bias: Optional[torch.Tensor] = None,
54
+ group_size: int = GROUP) -> torch.Tensor:
55
+ """int8 activations times packed binary weights -> bf16 ``[M, N]``."""
56
+ return ops.binary_gemm(act_q, act_scale, wq, wscale, bias, group_size)
57
+
58
+
59
+ def binary_linear(x: torch.Tensor, wq: torch.Tensor, wscale: torch.Tensor,
60
+ bias: Optional[torch.Tensor] = None,
61
+ group_size: int = GROUP) -> torch.Tensor:
62
+ """One-shot forward: quantize the activation, then the packed product.
63
+ Trailing batch dimensions are preserved."""
64
+ shape = x.shape[:-1]
65
+ q, s = quantize_activation(x)
66
+ out = binary_gemm(q, s, wq, wscale, bias, group_size)
67
+ return out.reshape(*shape, out.shape[-1])
68
+
69
+
70
+ class BinaryLinear(torch.nn.Module):
71
+ """Drop-in for a binary-weight ``nn.Linear``. Holds packed weights and their
72
+ group scales; nothing is stored at higher precision."""
73
+
74
+ def __init__(self, in_features: int, out_features: int, bias: bool = False,
75
+ group_size: int = GROUP, device=None):
76
+ super().__init__()
77
+ assert in_features % 32 == 0, "in_features must be a multiple of 32"
78
+ assert in_features % group_size == 0, "in_features must be a multiple of group_size"
79
+ self.in_features = in_features
80
+ self.out_features = out_features
81
+ self.group_size = group_size
82
+ self.register_buffer(
83
+ "wq", torch.zeros(out_features, in_features // 32, dtype=torch.int32,
84
+ device=device))
85
+ self.register_buffer(
86
+ "wscale", torch.ones(out_features, in_features // group_size,
87
+ dtype=torch.float16, device=device))
88
+ self.bias = torch.nn.Parameter(
89
+ torch.zeros(out_features, device=device)) if bias else None
90
+
91
+ @classmethod
92
+ def from_dense(cls, lin: torch.nn.Linear, group_size: int = GROUP) -> "BinaryLinear":
93
+ """Binarize an existing linear by sign, with the group scale set to the
94
+ group's mean absolute weight, which is the scale that minimizes squared
95
+ error for a sign-quantized group."""
96
+ W = lin.weight.data
97
+ N, K = W.shape
98
+ m = cls(K, N, bias=lin.bias is not None, group_size=group_size,
99
+ device=W.device)
100
+ signs = torch.where(W >= 0, 1, -1).to(torch.int8)
101
+ m.wq.copy_(pack_weights(signs))
102
+ m.wscale.copy_(W.reshape(N, K // group_size, group_size).abs().mean(-1)
103
+ .to(torch.float16))
104
+ if lin.bias is not None:
105
+ m.bias.data.copy_(lin.bias.data)
106
+ return m
107
+
108
+ def forward(self, x: torch.Tensor) -> torch.Tensor:
109
+ return binary_linear(x, self.wq, self.wscale, self.bias, self.group_size)
110
+
111
+ def extra_repr(self) -> str:
112
+ bits = 1 + 16 / self.group_size
113
+ return (f"in_features={self.in_features}, out_features={self.out_features}, "
114
+ f"group_size={self.group_size}, effective_bits={bits:.3f}")
build/torch213-cxx11-cu130-x86_64-linux/_binary_gemm_cuda_31ce78e.abi3.so ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:9a16adc9320c70979199f783d70716c648d7a4471ce5f926f584dc17283c0f05
3
+ size 687120
build/torch213-cxx11-cu130-x86_64-linux/_ops.py ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ import torch
2
+ from . import _binary_gemm_cuda_31ce78e
3
+ ops = torch.ops._binary_gemm_cuda_31ce78e
4
+
5
+ def add_op_namespace_prefix(op_name: str):
6
+ """
7
+ Prefix op by namespace.
8
+ """
9
+ return f"_binary_gemm_cuda_31ce78e::{op_name}"
build/torch213-cxx11-cu130-x86_64-linux/binary_gemm/__init__.py ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import ctypes
2
+ import importlib.util
3
+ import sys
4
+ from pathlib import Path
5
+ from types import ModuleType
6
+
7
+
8
+ def _import_from_path(file_path: Path) -> ModuleType:
9
+ # We cannot use the module name as-is, after adding it to `sys.modules`,
10
+ # it would also be used for other imports. So, we make a module name that
11
+ # depends on the path for it to be unique using the hex-encoded hash of
12
+ # the path.
13
+ path_hash = "{:x}".format(ctypes.c_size_t(hash(file_path.absolute())).value)
14
+ module_name = path_hash
15
+ spec = importlib.util.spec_from_file_location(module_name, file_path)
16
+ if spec is None:
17
+ raise ImportError(f"Cannot load spec for {module_name} from {file_path}")
18
+ module = importlib.util.module_from_spec(spec)
19
+ if module is None:
20
+ raise ImportError(f"Cannot load module {module_name} from spec")
21
+ sys.modules[module_name] = module
22
+ spec.loader.exec_module(module) # type: ignore
23
+ return module
24
+
25
+
26
+ globals().update(vars(_import_from_path(Path(__file__).parent.parent / "__init__.py")))
build/torch213-cxx11-cu130-x86_64-linux/metadata.json ADDED
@@ -0,0 +1,38 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "binary-gemm",
3
+ "id": "_binary_gemm_cuda_31ce78e",
4
+ "version": 1,
5
+ "license": "Apache-2.0",
6
+ "python-depends": [],
7
+ "backend": {
8
+ "type": "cuda",
9
+ "archs": [
10
+ "10.0",
11
+ "12.0",
12
+ "8.0",
13
+ "8.6",
14
+ "8.9",
15
+ "9.0"
16
+ ]
17
+ },
18
+ "digest": {
19
+ "algorithm": "sha256",
20
+ "files": {
21
+ "__init__.py": "fwn5WUojHrxLQwNl70+IAx7FZfHJQI9O+Zp5h4F+n7Y=",
22
+ "_binary_gemm_cuda_31ce78e.abi3.so": "mhatyTIMcJeRmfeD1wcWxkjXpEcc5fkm9YTcFyg8DwU=",
23
+ "_ops.py": "cGdYjoXrblpZs8DIqLlPArXWztTZ+wWrveEjvYq+5/0=",
24
+ "binary_gemm/__init__.py": "DFYPlrhXwYjEqCl/8n0SmWGZV8NFml5DPhMjKfv98GY="
25
+ }
26
+ },
27
+ "provenance": {
28
+ "kernel-builder": {
29
+ "version": "0.17.0-dev0",
30
+ "sha": "19aaa6421e674e9fecc352bbae6eab81d19a6bf4",
31
+ "dirty": false
32
+ },
33
+ "kernel": {
34
+ "sha": "31ce78ecfe5b53cd413fd76785b351410c1f610a",
35
+ "dirty": false
36
+ }
37
+ }
38
+ }
build/torch213-cxx11-cu132-x86_64-linux/__init__.py ADDED
@@ -0,0 +1,114 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """binary-gemm: W1A8 matrix products for binary-weight language models.
2
+
3
+ Each weight is one bit meaning +1 or -1, with one fp16 scale per group of G
4
+ weights: at G = 128 that is 1.125 effective bits, against 2 bits for a ternary
5
+ layer and 16 for bf16. Activations are quantized per token to int8.
6
+
7
+ Binary weights are not a special case of ternary. Writing the stored bit as
8
+ b = (w + 1) / 2, the inner product is 2 * sum_{b_i = 1} a_i - sum_i a_i, so the
9
+ weight is never materialized as a number. The kernel resolves four weights at a
10
+ time through a nibble table feeding __dp4a.
11
+
12
+ Ternary companions on the Hub: phanerozoic/bitnet-tc (CUDA),
13
+ phanerozoic/bitnet-cpu (CPU).
14
+ """
15
+ from typing import Optional, Tuple
16
+
17
+ import torch
18
+
19
+ from ._ops import ops
20
+
21
+ __all__ = [
22
+ "pack_weights", "unpack_weights", "quantize_activation", "binary_gemm",
23
+ "binary_linear", "BinaryLinear",
24
+ ]
25
+
26
+ GROUP = 128
27
+
28
+
29
+ def pack_weights(w: torch.Tensor) -> torch.Tensor:
30
+ """Pack a ``{-1, +1}`` int8 ``[N, K]`` matrix to ``[N, K//32]`` int32.
31
+
32
+ Bit j of word i holds weight ``32*i + j``: set means +1, clear means -1.
33
+ Zeros are treated as -1, so a ternary tensor will not round-trip.
34
+ """
35
+ return ops.pack_weights(w.contiguous().to(torch.int8))
36
+
37
+
38
+ def unpack_weights(wq: torch.Tensor, K: int) -> torch.Tensor:
39
+ """Inverse of :func:`pack_weights`, for tests and for a reference path."""
40
+ bits = wq.to(torch.int32)
41
+ idx = torch.arange(32, device=wq.device, dtype=torch.int32)
42
+ out = ((bits.unsqueeze(-1) >> idx) & 1).to(torch.int8)
43
+ return (out.reshape(wq.shape[0], -1)[:, :K] * 2 - 1)
44
+
45
+
46
+ def quantize_activation(x: torch.Tensor) -> Tuple[torch.Tensor, torch.Tensor]:
47
+ """bf16 ``[..., K]`` -> (int8 ``[M, K]``, fp32 per-token scale ``[M]``)."""
48
+ q, s = ops.quantize_activation(x.contiguous().to(torch.bfloat16))
49
+ return q, s
50
+
51
+
52
+ def binary_gemm(act_q: torch.Tensor, act_scale: torch.Tensor, wq: torch.Tensor,
53
+ wscale: torch.Tensor, bias: Optional[torch.Tensor] = None,
54
+ group_size: int = GROUP) -> torch.Tensor:
55
+ """int8 activations times packed binary weights -> bf16 ``[M, N]``."""
56
+ return ops.binary_gemm(act_q, act_scale, wq, wscale, bias, group_size)
57
+
58
+
59
+ def binary_linear(x: torch.Tensor, wq: torch.Tensor, wscale: torch.Tensor,
60
+ bias: Optional[torch.Tensor] = None,
61
+ group_size: int = GROUP) -> torch.Tensor:
62
+ """One-shot forward: quantize the activation, then the packed product.
63
+ Trailing batch dimensions are preserved."""
64
+ shape = x.shape[:-1]
65
+ q, s = quantize_activation(x)
66
+ out = binary_gemm(q, s, wq, wscale, bias, group_size)
67
+ return out.reshape(*shape, out.shape[-1])
68
+
69
+
70
+ class BinaryLinear(torch.nn.Module):
71
+ """Drop-in for a binary-weight ``nn.Linear``. Holds packed weights and their
72
+ group scales; nothing is stored at higher precision."""
73
+
74
+ def __init__(self, in_features: int, out_features: int, bias: bool = False,
75
+ group_size: int = GROUP, device=None):
76
+ super().__init__()
77
+ assert in_features % 32 == 0, "in_features must be a multiple of 32"
78
+ assert in_features % group_size == 0, "in_features must be a multiple of group_size"
79
+ self.in_features = in_features
80
+ self.out_features = out_features
81
+ self.group_size = group_size
82
+ self.register_buffer(
83
+ "wq", torch.zeros(out_features, in_features // 32, dtype=torch.int32,
84
+ device=device))
85
+ self.register_buffer(
86
+ "wscale", torch.ones(out_features, in_features // group_size,
87
+ dtype=torch.float16, device=device))
88
+ self.bias = torch.nn.Parameter(
89
+ torch.zeros(out_features, device=device)) if bias else None
90
+
91
+ @classmethod
92
+ def from_dense(cls, lin: torch.nn.Linear, group_size: int = GROUP) -> "BinaryLinear":
93
+ """Binarize an existing linear by sign, with the group scale set to the
94
+ group's mean absolute weight, which is the scale that minimizes squared
95
+ error for a sign-quantized group."""
96
+ W = lin.weight.data
97
+ N, K = W.shape
98
+ m = cls(K, N, bias=lin.bias is not None, group_size=group_size,
99
+ device=W.device)
100
+ signs = torch.where(W >= 0, 1, -1).to(torch.int8)
101
+ m.wq.copy_(pack_weights(signs))
102
+ m.wscale.copy_(W.reshape(N, K // group_size, group_size).abs().mean(-1)
103
+ .to(torch.float16))
104
+ if lin.bias is not None:
105
+ m.bias.data.copy_(lin.bias.data)
106
+ return m
107
+
108
+ def forward(self, x: torch.Tensor) -> torch.Tensor:
109
+ return binary_linear(x, self.wq, self.wscale, self.bias, self.group_size)
110
+
111
+ def extra_repr(self) -> str:
112
+ bits = 1 + 16 / self.group_size
113
+ return (f"in_features={self.in_features}, out_features={self.out_features}, "
114
+ f"group_size={self.group_size}, effective_bits={bits:.3f}")
build/torch213-cxx11-cu132-x86_64-linux/_binary_gemm_cuda_31ce78e.abi3.so ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:c81218433482ffc1f9565ba27445822bd9e765fda89e15a6313ac62355416309
3
+ size 726032
build/torch213-cxx11-cu132-x86_64-linux/_ops.py ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ import torch
2
+ from . import _binary_gemm_cuda_31ce78e
3
+ ops = torch.ops._binary_gemm_cuda_31ce78e
4
+
5
+ def add_op_namespace_prefix(op_name: str):
6
+ """
7
+ Prefix op by namespace.
8
+ """
9
+ return f"_binary_gemm_cuda_31ce78e::{op_name}"
build/torch213-cxx11-cu132-x86_64-linux/binary_gemm/__init__.py ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import ctypes
2
+ import importlib.util
3
+ import sys
4
+ from pathlib import Path
5
+ from types import ModuleType
6
+
7
+
8
+ def _import_from_path(file_path: Path) -> ModuleType:
9
+ # We cannot use the module name as-is, after adding it to `sys.modules`,
10
+ # it would also be used for other imports. So, we make a module name that
11
+ # depends on the path for it to be unique using the hex-encoded hash of
12
+ # the path.
13
+ path_hash = "{:x}".format(ctypes.c_size_t(hash(file_path.absolute())).value)
14
+ module_name = path_hash
15
+ spec = importlib.util.spec_from_file_location(module_name, file_path)
16
+ if spec is None:
17
+ raise ImportError(f"Cannot load spec for {module_name} from {file_path}")
18
+ module = importlib.util.module_from_spec(spec)
19
+ if module is None:
20
+ raise ImportError(f"Cannot load module {module_name} from spec")
21
+ sys.modules[module_name] = module
22
+ spec.loader.exec_module(module) # type: ignore
23
+ return module
24
+
25
+
26
+ globals().update(vars(_import_from_path(Path(__file__).parent.parent / "__init__.py")))
build/torch213-cxx11-cu132-x86_64-linux/metadata.json ADDED
@@ -0,0 +1,38 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "binary-gemm",
3
+ "id": "_binary_gemm_cuda_31ce78e",
4
+ "version": 1,
5
+ "license": "Apache-2.0",
6
+ "python-depends": [],
7
+ "backend": {
8
+ "type": "cuda",
9
+ "archs": [
10
+ "10.0",
11
+ "12.0",
12
+ "8.0",
13
+ "8.6",
14
+ "8.9",
15
+ "9.0"
16
+ ]
17
+ },
18
+ "digest": {
19
+ "algorithm": "sha256",
20
+ "files": {
21
+ "__init__.py": "fwn5WUojHrxLQwNl70+IAx7FZfHJQI9O+Zp5h4F+n7Y=",
22
+ "_binary_gemm_cuda_31ce78e.abi3.so": "yBIYQzSC/8H5VluidEWCK9nnZf2onhWmMTrGI1VBYwk=",
23
+ "_ops.py": "cGdYjoXrblpZs8DIqLlPArXWztTZ+wWrveEjvYq+5/0=",
24
+ "binary_gemm/__init__.py": "DFYPlrhXwYjEqCl/8n0SmWGZV8NFml5DPhMjKfv98GY="
25
+ }
26
+ },
27
+ "provenance": {
28
+ "kernel-builder": {
29
+ "version": "0.17.0-dev0",
30
+ "sha": "19aaa6421e674e9fecc352bbae6eab81d19a6bf4",
31
+ "dirty": false
32
+ },
33
+ "kernel": {
34
+ "sha": "31ce78ecfe5b53cd413fd76785b351410c1f610a",
35
+ "dirty": false
36
+ }
37
+ }
38
+ }