phanerozoic commited on
Commit
d2fb457
·
verified ·
1 Parent(s): 18e03cb

Uploaded using `kernel-builder`.

Browse files
build/torch211-cxx11-cpu-x86_64-linux/__init__.py ADDED
@@ -0,0 +1,229 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """quant-matmul: W4A8 / W8A8 / FP16-storage GEMV-GEMM for CPUs, aarch64-first.
2
+
3
+ Int4 weights in GPTQ/AWQ-compatible group quantization run against per-token
4
+ INT8 activations on NEON (SDOT where the CPU has dotprod); an int8 W8A8 path
5
+ and an fp16-storage GEMV round out the pack. x86-64 runs a portable scalar
6
+ path (correct, not tuned).
7
+
8
+ High-level API:
9
+ pack_w4(intw, scales, zeros, group_size) native packing from raw nibbles
10
+ from_gptq(qweight, qzeros, scales, g_idx) GPTQ checkpoint tensors -> native
11
+ from_awq(qweight, qzeros, scales) AWQ checkpoint tensors -> native
12
+ w4a8_linear(x, packed, scales, zeros, group_size, perm)
13
+ w8a8_linear(x, w_int8, scale_wt)
14
+ fp16_gemv(x, w_f16)
15
+ QuantLinear nn.Module wrapper
16
+ """
17
+ from typing import Optional, Tuple
18
+
19
+ import torch
20
+ import torch.nn as nn
21
+
22
+ from ._ops import ops
23
+
24
+ _OK_DTYPES = (torch.bfloat16, torch.float32)
25
+
26
+
27
+ def pack_w4(intw: torch.Tensor, scales: torch.Tensor, zeros: torch.Tensor,
28
+ group_size: int):
29
+ """Pack int4 nibbles into the native layout.
30
+
31
+ Args:
32
+ intw: [N, K] integer tensor with values 0..15.
33
+ scales: [N, G] per-group scales (G = K // group_size).
34
+ zeros: [N, G] per-group zero points, already in subtract-this form.
35
+ Returns:
36
+ (packed uint8 [N, K/2], scales f32 [N, G], zeros f32 [N, G])
37
+ """
38
+ assert intw.dim() == 2, "intw must be [N, K]"
39
+ N, K = intw.shape
40
+ assert K % group_size == 0 and group_size % 32 == 0
41
+ w = intw.to(torch.uint8)
42
+ assert int(w.max()) <= 15, "nibbles must be 0..15"
43
+ packed = (w[:, 0::2] | (w[:, 1::2] << 4)).contiguous()
44
+ G = K // group_size
45
+ s = scales.to(torch.float32).reshape(N, G).contiguous()
46
+ z = zeros.to(torch.float32).reshape(N, G).contiguous()
47
+ return packed, s, z
48
+
49
+
50
+ def dequant_w4(packed: torch.Tensor, scales: torch.Tensor, zeros: torch.Tensor,
51
+ group_size: int) -> torch.Tensor:
52
+ """Reference dequantization to f32 [N, K] (tests and debugging)."""
53
+ N = packed.shape[0]
54
+ K = packed.shape[1] * 2
55
+ nib = torch.empty(N, K, dtype=torch.float32)
56
+ nib[:, 0::2] = (packed & 0xF).float()
57
+ nib[:, 1::2] = (packed >> 4).float()
58
+ G = K // group_size
59
+ z = zeros.reshape(N, G, 1)
60
+ s = scales.reshape(N, G, 1)
61
+ return ((nib.reshape(N, G, group_size) - z) * s).reshape(N, K)
62
+
63
+
64
+ _GPTQ_SHIFTS = torch.arange(0, 32, 4, dtype=torch.int32)
65
+
66
+
67
+ def _unpack_int32_nibbles(t: torch.Tensor, dim_factor: int = 8) -> torch.Tensor:
68
+ """int32 [..., P] -> uint8 [..., P*8], nibble j of each word at index 8p+j."""
69
+ u = ((t.unsqueeze(-1) >> _GPTQ_SHIFTS) & 0xF).to(torch.uint8)
70
+ return u.reshape(*t.shape[:-1], t.shape[-1] * dim_factor)
71
+
72
+
73
+ def from_gptq(qweight: torch.Tensor, qzeros: torch.Tensor, scales: torch.Tensor,
74
+ g_idx: Optional[torch.Tensor] = None, zero_offset: int = 1):
75
+ """GPTQ checkpoint tensors -> native packing.
76
+
77
+ qweight int32 [K/8, N]; qzeros int32 [G, N/8]; scales [G, N].
78
+ zero_offset follows the AutoGPTQ storage convention (stored zero + 1 is
79
+ subtracted at dequant); pass 0 for checkpoints without it.
80
+ Returns (packed, scales, zeros, group_size, perm) where perm is the
81
+ activation permutation for act-order checkpoints (None otherwise).
82
+ """
83
+ K = qweight.shape[0] * 8
84
+ N = qweight.shape[1]
85
+ G = scales.shape[0]
86
+ assert K % G == 0
87
+ group_size = K // G
88
+ # nibble j of qweight word [i, n] decodes k = 8i + j.
89
+ intw = _unpack_int32_nibbles(qweight.t().contiguous()) # [N, K]
90
+ z = (_unpack_int32_nibbles(qzeros).to(torch.float32) + float(zero_offset))
91
+ z = z.t().contiguous() # [N, G]
92
+ s = scales.t().to(torch.float32).contiguous() # [N, G]
93
+ perm = None
94
+ if g_idx is not None:
95
+ trivial = torch.arange(K, dtype=g_idx.dtype) // group_size
96
+ if not torch.equal(g_idx.cpu(), trivial):
97
+ perm = torch.argsort(g_idx.cpu(), stable=True)
98
+ intw = intw[:, perm]
99
+ packed, s, z = pack_w4(intw, s, z, group_size)
100
+ return packed, s, z, group_size, perm
101
+
102
+
103
+ _AWQ_ORDER = [0, 2, 4, 6, 1, 3, 5, 7]
104
+
105
+
106
+ def from_awq(qweight: torch.Tensor, qzeros: torch.Tensor, scales: torch.Tensor,
107
+ zero_offset: int = 0):
108
+ """AWQ (AutoAWQ GEMM) checkpoint tensors -> native packing.
109
+
110
+ qweight int32 [K, N/8] with nibble order [0,2,4,6,1,3,5,7]; qzeros int32
111
+ [G, N/8] same order; scales [G, N].
112
+ Returns (packed, scales, zeros, group_size, None).
113
+ """
114
+ K = qweight.shape[0]
115
+ G = scales.shape[0]
116
+ N = scales.shape[1]
117
+ group_size = K // G
118
+ inv = torch.empty(8, dtype=torch.int64)
119
+ for j, o in enumerate(_AWQ_ORDER):
120
+ inv[o] = j
121
+ u = _unpack_int32_nibbles(qweight) # [K, N] j-order
122
+ u = u.reshape(K, N // 8, 8)[:, :, inv].reshape(K, N)
123
+ z = _unpack_int32_nibbles(qzeros).to(torch.float32) # [G, N] j-order
124
+ z = z.reshape(G, N // 8, 8)[:, :, inv].reshape(G, N) + float(zero_offset)
125
+ packed, s, z = pack_w4(u.t().contiguous(), scales.t(), z.t(), group_size)
126
+ return packed, s, z, group_size, None
127
+
128
+
129
+ def quantize_activation(x: torch.Tensor):
130
+ """Per-token absmax INT8: [..., K] bf16/f32 -> (int8 [M, K], f32 scale [M])."""
131
+ x_flat = x.reshape(-1, x.shape[-1]).contiguous()
132
+ M, K = x_flat.shape
133
+ x_int8 = torch.empty((M, K), dtype=torch.int8)
134
+ scale = torch.empty((M,), dtype=torch.float32)
135
+ ops.qm_quantize_act(x_int8, scale, x_flat)
136
+ return x_int8, scale
137
+
138
+
139
+ def w4a8_linear(x: torch.Tensor, packed: torch.Tensor, scales: torch.Tensor,
140
+ zeros: torch.Tensor, group_size: int,
141
+ perm: Optional[torch.Tensor] = None) -> torch.Tensor:
142
+ """W4A8 forward: [..., K] bf16/f32 -> [..., N], dtype follows x."""
143
+ assert x.dtype in _OK_DTYPES, f"x must be bf16 or f32, got {x.dtype}"
144
+ orig = x.shape
145
+ x_flat = x.reshape(-1, orig[-1])
146
+ if perm is not None:
147
+ x_flat = x_flat[:, perm]
148
+ x_flat = x_flat.contiguous()
149
+ M = x_flat.shape[0]
150
+ N = packed.shape[0]
151
+ out = torch.empty((M, N), dtype=x.dtype)
152
+ if M < 16:
153
+ ops.qm_w4a8_gemv_fused(out, x_flat, packed, scales, zeros, group_size)
154
+ else:
155
+ q, sa = quantize_activation(x_flat)
156
+ ops.qm_w4a8_gemm(out, q, packed, scales, zeros, sa, group_size)
157
+ return out.view(*orig[:-1], N)
158
+
159
+
160
+ def w8a8_linear(x: torch.Tensor, w_int8: torch.Tensor,
161
+ scale_wt: torch.Tensor) -> torch.Tensor:
162
+ """W8A8 forward: per-token int8 activations x int8 weights, per-row scale."""
163
+ assert x.dtype in _OK_DTYPES
164
+ orig = x.shape
165
+ q, sa = quantize_activation(x.reshape(-1, orig[-1]))
166
+ N = w_int8.shape[0]
167
+ out = torch.empty((q.shape[0], N), dtype=x.dtype)
168
+ ops.qm_w8a8_gemm(out, q, w_int8, sa, scale_wt)
169
+ return out.view(*orig[:-1], N)
170
+
171
+
172
+ def fp16_gemv(x: torch.Tensor, w_f16: torch.Tensor) -> torch.Tensor:
173
+ """fp16-storage GEMV: f16 weights widened to f32 in registers."""
174
+ orig = x.shape
175
+ x_flat = x.reshape(-1, orig[-1]).to(torch.float32).contiguous()
176
+ N = w_f16.shape[0]
177
+ out = torch.empty((x_flat.shape[0], N), dtype=torch.float32)
178
+ ops.qm_fp16_gemv(out, x_flat, w_f16)
179
+ return out.view(*orig[:-1], N).to(x.dtype)
180
+
181
+
182
+ class QuantLinear(nn.Module):
183
+ """Inference-only W4A8 linear over the native packing."""
184
+
185
+ def __init__(self, packed, scales, zeros, group_size, perm=None, bias=None):
186
+ super().__init__()
187
+ self.register_buffer("packed", packed)
188
+ self.register_buffer("scales", scales)
189
+ self.register_buffer("zeros", zeros)
190
+ self.group_size = int(group_size)
191
+ if perm is not None:
192
+ self.register_buffer("perm", perm)
193
+ else:
194
+ self.perm = None
195
+ if bias is not None:
196
+ self.register_buffer("bias", bias)
197
+ else:
198
+ self.bias = None
199
+
200
+ @classmethod
201
+ def from_gptq_tensors(cls, qweight, qzeros, scales, g_idx=None, bias=None,
202
+ zero_offset=1):
203
+ packed, s, z, gs, perm = from_gptq(qweight, qzeros, scales, g_idx, zero_offset)
204
+ return cls(packed, s, z, gs, perm, bias)
205
+
206
+ @classmethod
207
+ def from_awq_tensors(cls, qweight, qzeros, scales, bias=None, zero_offset=0):
208
+ packed, s, z, gs, perm = from_awq(qweight, qzeros, scales, zero_offset)
209
+ return cls(packed, s, z, gs, perm, bias)
210
+
211
+ def forward(self, x: torch.Tensor) -> torch.Tensor:
212
+ y = w4a8_linear(x, self.packed, self.scales, self.zeros, self.group_size,
213
+ self.perm)
214
+ if self.bias is not None:
215
+ y = y + self.bias
216
+ return y
217
+
218
+
219
+ __all__ = [
220
+ "pack_w4",
221
+ "dequant_w4",
222
+ "from_gptq",
223
+ "from_awq",
224
+ "quantize_activation",
225
+ "w4a8_linear",
226
+ "w8a8_linear",
227
+ "fp16_gemv",
228
+ "QuantLinear",
229
+ ]
build/torch211-cxx11-cpu-x86_64-linux/_ops.py ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ import torch
2
+ from . import _quant_matmul_cpu_18a2909
3
+ ops = torch.ops._quant_matmul_cpu_18a2909
4
+
5
+ def add_op_namespace_prefix(op_name: str):
6
+ """
7
+ Prefix op by namespace.
8
+ """
9
+ return f"_quant_matmul_cpu_18a2909::{op_name}"
build/torch211-cxx11-cpu-x86_64-linux/_quant_matmul_cpu_18a2909.abi3.so ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:cb00d2b295b018acc9a42048bf276c3d9c5dfe99077ac267e6c45f774bbbf403
3
+ size 143032
build/torch211-cxx11-cpu-x86_64-linux/metadata.json ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "quant-matmul",
3
+ "id": "_quant_matmul_cpu_18a2909",
4
+ "version": 1,
5
+ "license": "Apache-2.0",
6
+ "python-depends": [],
7
+ "backend": {
8
+ "type": "cpu"
9
+ },
10
+ "digest": {
11
+ "algorithm": "sha256",
12
+ "files": {
13
+ "__init__.py": "FTTRodgwtEJbDPRdBoeZdVWC5sDL6EpzX8St+v6bUyI=",
14
+ "_ops.py": "7XG0r+IuC4ujAoIFN6lqK2qfTCKug4asMH3GvteKiuw=",
15
+ "_quant_matmul_cpu_18a2909.abi3.so": "ywDSspWwGKzJpCBIvydsPZxd/pkHesJn5sRfd0u79AM=",
16
+ "quant_matmul/__init__.py": "DFYPlrhXwYjEqCl/8n0SmWGZV8NFml5DPhMjKfv98GY="
17
+ }
18
+ },
19
+ "provenance": {
20
+ "kernel-builder": {
21
+ "version": "0.17.0-dev0",
22
+ "sha": "19aaa6421e674e9fecc352bbae6eab81d19a6bf4",
23
+ "dirty": false
24
+ },
25
+ "kernel": {
26
+ "sha": "18a2909d5970949d8ec3915c4062d6c3c05466e8",
27
+ "dirty": false
28
+ }
29
+ }
30
+ }
build/torch211-cxx11-cpu-x86_64-linux/quant_matmul/__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-cpu-x86_64-linux/__init__.py ADDED
@@ -0,0 +1,229 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """quant-matmul: W4A8 / W8A8 / FP16-storage GEMV-GEMM for CPUs, aarch64-first.
2
+
3
+ Int4 weights in GPTQ/AWQ-compatible group quantization run against per-token
4
+ INT8 activations on NEON (SDOT where the CPU has dotprod); an int8 W8A8 path
5
+ and an fp16-storage GEMV round out the pack. x86-64 runs a portable scalar
6
+ path (correct, not tuned).
7
+
8
+ High-level API:
9
+ pack_w4(intw, scales, zeros, group_size) native packing from raw nibbles
10
+ from_gptq(qweight, qzeros, scales, g_idx) GPTQ checkpoint tensors -> native
11
+ from_awq(qweight, qzeros, scales) AWQ checkpoint tensors -> native
12
+ w4a8_linear(x, packed, scales, zeros, group_size, perm)
13
+ w8a8_linear(x, w_int8, scale_wt)
14
+ fp16_gemv(x, w_f16)
15
+ QuantLinear nn.Module wrapper
16
+ """
17
+ from typing import Optional, Tuple
18
+
19
+ import torch
20
+ import torch.nn as nn
21
+
22
+ from ._ops import ops
23
+
24
+ _OK_DTYPES = (torch.bfloat16, torch.float32)
25
+
26
+
27
+ def pack_w4(intw: torch.Tensor, scales: torch.Tensor, zeros: torch.Tensor,
28
+ group_size: int):
29
+ """Pack int4 nibbles into the native layout.
30
+
31
+ Args:
32
+ intw: [N, K] integer tensor with values 0..15.
33
+ scales: [N, G] per-group scales (G = K // group_size).
34
+ zeros: [N, G] per-group zero points, already in subtract-this form.
35
+ Returns:
36
+ (packed uint8 [N, K/2], scales f32 [N, G], zeros f32 [N, G])
37
+ """
38
+ assert intw.dim() == 2, "intw must be [N, K]"
39
+ N, K = intw.shape
40
+ assert K % group_size == 0 and group_size % 32 == 0
41
+ w = intw.to(torch.uint8)
42
+ assert int(w.max()) <= 15, "nibbles must be 0..15"
43
+ packed = (w[:, 0::2] | (w[:, 1::2] << 4)).contiguous()
44
+ G = K // group_size
45
+ s = scales.to(torch.float32).reshape(N, G).contiguous()
46
+ z = zeros.to(torch.float32).reshape(N, G).contiguous()
47
+ return packed, s, z
48
+
49
+
50
+ def dequant_w4(packed: torch.Tensor, scales: torch.Tensor, zeros: torch.Tensor,
51
+ group_size: int) -> torch.Tensor:
52
+ """Reference dequantization to f32 [N, K] (tests and debugging)."""
53
+ N = packed.shape[0]
54
+ K = packed.shape[1] * 2
55
+ nib = torch.empty(N, K, dtype=torch.float32)
56
+ nib[:, 0::2] = (packed & 0xF).float()
57
+ nib[:, 1::2] = (packed >> 4).float()
58
+ G = K // group_size
59
+ z = zeros.reshape(N, G, 1)
60
+ s = scales.reshape(N, G, 1)
61
+ return ((nib.reshape(N, G, group_size) - z) * s).reshape(N, K)
62
+
63
+
64
+ _GPTQ_SHIFTS = torch.arange(0, 32, 4, dtype=torch.int32)
65
+
66
+
67
+ def _unpack_int32_nibbles(t: torch.Tensor, dim_factor: int = 8) -> torch.Tensor:
68
+ """int32 [..., P] -> uint8 [..., P*8], nibble j of each word at index 8p+j."""
69
+ u = ((t.unsqueeze(-1) >> _GPTQ_SHIFTS) & 0xF).to(torch.uint8)
70
+ return u.reshape(*t.shape[:-1], t.shape[-1] * dim_factor)
71
+
72
+
73
+ def from_gptq(qweight: torch.Tensor, qzeros: torch.Tensor, scales: torch.Tensor,
74
+ g_idx: Optional[torch.Tensor] = None, zero_offset: int = 1):
75
+ """GPTQ checkpoint tensors -> native packing.
76
+
77
+ qweight int32 [K/8, N]; qzeros int32 [G, N/8]; scales [G, N].
78
+ zero_offset follows the AutoGPTQ storage convention (stored zero + 1 is
79
+ subtracted at dequant); pass 0 for checkpoints without it.
80
+ Returns (packed, scales, zeros, group_size, perm) where perm is the
81
+ activation permutation for act-order checkpoints (None otherwise).
82
+ """
83
+ K = qweight.shape[0] * 8
84
+ N = qweight.shape[1]
85
+ G = scales.shape[0]
86
+ assert K % G == 0
87
+ group_size = K // G
88
+ # nibble j of qweight word [i, n] decodes k = 8i + j.
89
+ intw = _unpack_int32_nibbles(qweight.t().contiguous()) # [N, K]
90
+ z = (_unpack_int32_nibbles(qzeros).to(torch.float32) + float(zero_offset))
91
+ z = z.t().contiguous() # [N, G]
92
+ s = scales.t().to(torch.float32).contiguous() # [N, G]
93
+ perm = None
94
+ if g_idx is not None:
95
+ trivial = torch.arange(K, dtype=g_idx.dtype) // group_size
96
+ if not torch.equal(g_idx.cpu(), trivial):
97
+ perm = torch.argsort(g_idx.cpu(), stable=True)
98
+ intw = intw[:, perm]
99
+ packed, s, z = pack_w4(intw, s, z, group_size)
100
+ return packed, s, z, group_size, perm
101
+
102
+
103
+ _AWQ_ORDER = [0, 2, 4, 6, 1, 3, 5, 7]
104
+
105
+
106
+ def from_awq(qweight: torch.Tensor, qzeros: torch.Tensor, scales: torch.Tensor,
107
+ zero_offset: int = 0):
108
+ """AWQ (AutoAWQ GEMM) checkpoint tensors -> native packing.
109
+
110
+ qweight int32 [K, N/8] with nibble order [0,2,4,6,1,3,5,7]; qzeros int32
111
+ [G, N/8] same order; scales [G, N].
112
+ Returns (packed, scales, zeros, group_size, None).
113
+ """
114
+ K = qweight.shape[0]
115
+ G = scales.shape[0]
116
+ N = scales.shape[1]
117
+ group_size = K // G
118
+ inv = torch.empty(8, dtype=torch.int64)
119
+ for j, o in enumerate(_AWQ_ORDER):
120
+ inv[o] = j
121
+ u = _unpack_int32_nibbles(qweight) # [K, N] j-order
122
+ u = u.reshape(K, N // 8, 8)[:, :, inv].reshape(K, N)
123
+ z = _unpack_int32_nibbles(qzeros).to(torch.float32) # [G, N] j-order
124
+ z = z.reshape(G, N // 8, 8)[:, :, inv].reshape(G, N) + float(zero_offset)
125
+ packed, s, z = pack_w4(u.t().contiguous(), scales.t(), z.t(), group_size)
126
+ return packed, s, z, group_size, None
127
+
128
+
129
+ def quantize_activation(x: torch.Tensor):
130
+ """Per-token absmax INT8: [..., K] bf16/f32 -> (int8 [M, K], f32 scale [M])."""
131
+ x_flat = x.reshape(-1, x.shape[-1]).contiguous()
132
+ M, K = x_flat.shape
133
+ x_int8 = torch.empty((M, K), dtype=torch.int8)
134
+ scale = torch.empty((M,), dtype=torch.float32)
135
+ ops.qm_quantize_act(x_int8, scale, x_flat)
136
+ return x_int8, scale
137
+
138
+
139
+ def w4a8_linear(x: torch.Tensor, packed: torch.Tensor, scales: torch.Tensor,
140
+ zeros: torch.Tensor, group_size: int,
141
+ perm: Optional[torch.Tensor] = None) -> torch.Tensor:
142
+ """W4A8 forward: [..., K] bf16/f32 -> [..., N], dtype follows x."""
143
+ assert x.dtype in _OK_DTYPES, f"x must be bf16 or f32, got {x.dtype}"
144
+ orig = x.shape
145
+ x_flat = x.reshape(-1, orig[-1])
146
+ if perm is not None:
147
+ x_flat = x_flat[:, perm]
148
+ x_flat = x_flat.contiguous()
149
+ M = x_flat.shape[0]
150
+ N = packed.shape[0]
151
+ out = torch.empty((M, N), dtype=x.dtype)
152
+ if M < 16:
153
+ ops.qm_w4a8_gemv_fused(out, x_flat, packed, scales, zeros, group_size)
154
+ else:
155
+ q, sa = quantize_activation(x_flat)
156
+ ops.qm_w4a8_gemm(out, q, packed, scales, zeros, sa, group_size)
157
+ return out.view(*orig[:-1], N)
158
+
159
+
160
+ def w8a8_linear(x: torch.Tensor, w_int8: torch.Tensor,
161
+ scale_wt: torch.Tensor) -> torch.Tensor:
162
+ """W8A8 forward: per-token int8 activations x int8 weights, per-row scale."""
163
+ assert x.dtype in _OK_DTYPES
164
+ orig = x.shape
165
+ q, sa = quantize_activation(x.reshape(-1, orig[-1]))
166
+ N = w_int8.shape[0]
167
+ out = torch.empty((q.shape[0], N), dtype=x.dtype)
168
+ ops.qm_w8a8_gemm(out, q, w_int8, sa, scale_wt)
169
+ return out.view(*orig[:-1], N)
170
+
171
+
172
+ def fp16_gemv(x: torch.Tensor, w_f16: torch.Tensor) -> torch.Tensor:
173
+ """fp16-storage GEMV: f16 weights widened to f32 in registers."""
174
+ orig = x.shape
175
+ x_flat = x.reshape(-1, orig[-1]).to(torch.float32).contiguous()
176
+ N = w_f16.shape[0]
177
+ out = torch.empty((x_flat.shape[0], N), dtype=torch.float32)
178
+ ops.qm_fp16_gemv(out, x_flat, w_f16)
179
+ return out.view(*orig[:-1], N).to(x.dtype)
180
+
181
+
182
+ class QuantLinear(nn.Module):
183
+ """Inference-only W4A8 linear over the native packing."""
184
+
185
+ def __init__(self, packed, scales, zeros, group_size, perm=None, bias=None):
186
+ super().__init__()
187
+ self.register_buffer("packed", packed)
188
+ self.register_buffer("scales", scales)
189
+ self.register_buffer("zeros", zeros)
190
+ self.group_size = int(group_size)
191
+ if perm is not None:
192
+ self.register_buffer("perm", perm)
193
+ else:
194
+ self.perm = None
195
+ if bias is not None:
196
+ self.register_buffer("bias", bias)
197
+ else:
198
+ self.bias = None
199
+
200
+ @classmethod
201
+ def from_gptq_tensors(cls, qweight, qzeros, scales, g_idx=None, bias=None,
202
+ zero_offset=1):
203
+ packed, s, z, gs, perm = from_gptq(qweight, qzeros, scales, g_idx, zero_offset)
204
+ return cls(packed, s, z, gs, perm, bias)
205
+
206
+ @classmethod
207
+ def from_awq_tensors(cls, qweight, qzeros, scales, bias=None, zero_offset=0):
208
+ packed, s, z, gs, perm = from_awq(qweight, qzeros, scales, zero_offset)
209
+ return cls(packed, s, z, gs, perm, bias)
210
+
211
+ def forward(self, x: torch.Tensor) -> torch.Tensor:
212
+ y = w4a8_linear(x, self.packed, self.scales, self.zeros, self.group_size,
213
+ self.perm)
214
+ if self.bias is not None:
215
+ y = y + self.bias
216
+ return y
217
+
218
+
219
+ __all__ = [
220
+ "pack_w4",
221
+ "dequant_w4",
222
+ "from_gptq",
223
+ "from_awq",
224
+ "quantize_activation",
225
+ "w4a8_linear",
226
+ "w8a8_linear",
227
+ "fp16_gemv",
228
+ "QuantLinear",
229
+ ]
build/torch212-cxx11-cpu-x86_64-linux/_ops.py ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ import torch
2
+ from . import _quant_matmul_cpu_18a2909
3
+ ops = torch.ops._quant_matmul_cpu_18a2909
4
+
5
+ def add_op_namespace_prefix(op_name: str):
6
+ """
7
+ Prefix op by namespace.
8
+ """
9
+ return f"_quant_matmul_cpu_18a2909::{op_name}"
build/torch212-cxx11-cpu-x86_64-linux/_quant_matmul_cpu_18a2909.abi3.so ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:4b7aab09304bfdb2a5e7ab767a859f4d2f21d545b2bb3d00944e5c26a291d65b
3
+ size 147104
build/torch212-cxx11-cpu-x86_64-linux/metadata.json ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "quant-matmul",
3
+ "id": "_quant_matmul_cpu_18a2909",
4
+ "version": 1,
5
+ "license": "Apache-2.0",
6
+ "python-depends": [],
7
+ "backend": {
8
+ "type": "cpu"
9
+ },
10
+ "digest": {
11
+ "algorithm": "sha256",
12
+ "files": {
13
+ "__init__.py": "FTTRodgwtEJbDPRdBoeZdVWC5sDL6EpzX8St+v6bUyI=",
14
+ "_ops.py": "7XG0r+IuC4ujAoIFN6lqK2qfTCKug4asMH3GvteKiuw=",
15
+ "_quant_matmul_cpu_18a2909.abi3.so": "S3qrCTBL/bKl56t2eoWfTS8h1UWyuz0AlE5cJqKR1ls=",
16
+ "quant_matmul/__init__.py": "DFYPlrhXwYjEqCl/8n0SmWGZV8NFml5DPhMjKfv98GY="
17
+ }
18
+ },
19
+ "provenance": {
20
+ "kernel-builder": {
21
+ "version": "0.17.0-dev0",
22
+ "sha": "19aaa6421e674e9fecc352bbae6eab81d19a6bf4",
23
+ "dirty": false
24
+ },
25
+ "kernel": {
26
+ "sha": "18a2909d5970949d8ec3915c4062d6c3c05466e8",
27
+ "dirty": false
28
+ }
29
+ }
30
+ }
build/torch212-cxx11-cpu-x86_64-linux/quant_matmul/__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-cpu-x86_64-linux/__init__.py ADDED
@@ -0,0 +1,229 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """quant-matmul: W4A8 / W8A8 / FP16-storage GEMV-GEMM for CPUs, aarch64-first.
2
+
3
+ Int4 weights in GPTQ/AWQ-compatible group quantization run against per-token
4
+ INT8 activations on NEON (SDOT where the CPU has dotprod); an int8 W8A8 path
5
+ and an fp16-storage GEMV round out the pack. x86-64 runs a portable scalar
6
+ path (correct, not tuned).
7
+
8
+ High-level API:
9
+ pack_w4(intw, scales, zeros, group_size) native packing from raw nibbles
10
+ from_gptq(qweight, qzeros, scales, g_idx) GPTQ checkpoint tensors -> native
11
+ from_awq(qweight, qzeros, scales) AWQ checkpoint tensors -> native
12
+ w4a8_linear(x, packed, scales, zeros, group_size, perm)
13
+ w8a8_linear(x, w_int8, scale_wt)
14
+ fp16_gemv(x, w_f16)
15
+ QuantLinear nn.Module wrapper
16
+ """
17
+ from typing import Optional, Tuple
18
+
19
+ import torch
20
+ import torch.nn as nn
21
+
22
+ from ._ops import ops
23
+
24
+ _OK_DTYPES = (torch.bfloat16, torch.float32)
25
+
26
+
27
+ def pack_w4(intw: torch.Tensor, scales: torch.Tensor, zeros: torch.Tensor,
28
+ group_size: int):
29
+ """Pack int4 nibbles into the native layout.
30
+
31
+ Args:
32
+ intw: [N, K] integer tensor with values 0..15.
33
+ scales: [N, G] per-group scales (G = K // group_size).
34
+ zeros: [N, G] per-group zero points, already in subtract-this form.
35
+ Returns:
36
+ (packed uint8 [N, K/2], scales f32 [N, G], zeros f32 [N, G])
37
+ """
38
+ assert intw.dim() == 2, "intw must be [N, K]"
39
+ N, K = intw.shape
40
+ assert K % group_size == 0 and group_size % 32 == 0
41
+ w = intw.to(torch.uint8)
42
+ assert int(w.max()) <= 15, "nibbles must be 0..15"
43
+ packed = (w[:, 0::2] | (w[:, 1::2] << 4)).contiguous()
44
+ G = K // group_size
45
+ s = scales.to(torch.float32).reshape(N, G).contiguous()
46
+ z = zeros.to(torch.float32).reshape(N, G).contiguous()
47
+ return packed, s, z
48
+
49
+
50
+ def dequant_w4(packed: torch.Tensor, scales: torch.Tensor, zeros: torch.Tensor,
51
+ group_size: int) -> torch.Tensor:
52
+ """Reference dequantization to f32 [N, K] (tests and debugging)."""
53
+ N = packed.shape[0]
54
+ K = packed.shape[1] * 2
55
+ nib = torch.empty(N, K, dtype=torch.float32)
56
+ nib[:, 0::2] = (packed & 0xF).float()
57
+ nib[:, 1::2] = (packed >> 4).float()
58
+ G = K // group_size
59
+ z = zeros.reshape(N, G, 1)
60
+ s = scales.reshape(N, G, 1)
61
+ return ((nib.reshape(N, G, group_size) - z) * s).reshape(N, K)
62
+
63
+
64
+ _GPTQ_SHIFTS = torch.arange(0, 32, 4, dtype=torch.int32)
65
+
66
+
67
+ def _unpack_int32_nibbles(t: torch.Tensor, dim_factor: int = 8) -> torch.Tensor:
68
+ """int32 [..., P] -> uint8 [..., P*8], nibble j of each word at index 8p+j."""
69
+ u = ((t.unsqueeze(-1) >> _GPTQ_SHIFTS) & 0xF).to(torch.uint8)
70
+ return u.reshape(*t.shape[:-1], t.shape[-1] * dim_factor)
71
+
72
+
73
+ def from_gptq(qweight: torch.Tensor, qzeros: torch.Tensor, scales: torch.Tensor,
74
+ g_idx: Optional[torch.Tensor] = None, zero_offset: int = 1):
75
+ """GPTQ checkpoint tensors -> native packing.
76
+
77
+ qweight int32 [K/8, N]; qzeros int32 [G, N/8]; scales [G, N].
78
+ zero_offset follows the AutoGPTQ storage convention (stored zero + 1 is
79
+ subtracted at dequant); pass 0 for checkpoints without it.
80
+ Returns (packed, scales, zeros, group_size, perm) where perm is the
81
+ activation permutation for act-order checkpoints (None otherwise).
82
+ """
83
+ K = qweight.shape[0] * 8
84
+ N = qweight.shape[1]
85
+ G = scales.shape[0]
86
+ assert K % G == 0
87
+ group_size = K // G
88
+ # nibble j of qweight word [i, n] decodes k = 8i + j.
89
+ intw = _unpack_int32_nibbles(qweight.t().contiguous()) # [N, K]
90
+ z = (_unpack_int32_nibbles(qzeros).to(torch.float32) + float(zero_offset))
91
+ z = z.t().contiguous() # [N, G]
92
+ s = scales.t().to(torch.float32).contiguous() # [N, G]
93
+ perm = None
94
+ if g_idx is not None:
95
+ trivial = torch.arange(K, dtype=g_idx.dtype) // group_size
96
+ if not torch.equal(g_idx.cpu(), trivial):
97
+ perm = torch.argsort(g_idx.cpu(), stable=True)
98
+ intw = intw[:, perm]
99
+ packed, s, z = pack_w4(intw, s, z, group_size)
100
+ return packed, s, z, group_size, perm
101
+
102
+
103
+ _AWQ_ORDER = [0, 2, 4, 6, 1, 3, 5, 7]
104
+
105
+
106
+ def from_awq(qweight: torch.Tensor, qzeros: torch.Tensor, scales: torch.Tensor,
107
+ zero_offset: int = 0):
108
+ """AWQ (AutoAWQ GEMM) checkpoint tensors -> native packing.
109
+
110
+ qweight int32 [K, N/8] with nibble order [0,2,4,6,1,3,5,7]; qzeros int32
111
+ [G, N/8] same order; scales [G, N].
112
+ Returns (packed, scales, zeros, group_size, None).
113
+ """
114
+ K = qweight.shape[0]
115
+ G = scales.shape[0]
116
+ N = scales.shape[1]
117
+ group_size = K // G
118
+ inv = torch.empty(8, dtype=torch.int64)
119
+ for j, o in enumerate(_AWQ_ORDER):
120
+ inv[o] = j
121
+ u = _unpack_int32_nibbles(qweight) # [K, N] j-order
122
+ u = u.reshape(K, N // 8, 8)[:, :, inv].reshape(K, N)
123
+ z = _unpack_int32_nibbles(qzeros).to(torch.float32) # [G, N] j-order
124
+ z = z.reshape(G, N // 8, 8)[:, :, inv].reshape(G, N) + float(zero_offset)
125
+ packed, s, z = pack_w4(u.t().contiguous(), scales.t(), z.t(), group_size)
126
+ return packed, s, z, group_size, None
127
+
128
+
129
+ def quantize_activation(x: torch.Tensor):
130
+ """Per-token absmax INT8: [..., K] bf16/f32 -> (int8 [M, K], f32 scale [M])."""
131
+ x_flat = x.reshape(-1, x.shape[-1]).contiguous()
132
+ M, K = x_flat.shape
133
+ x_int8 = torch.empty((M, K), dtype=torch.int8)
134
+ scale = torch.empty((M,), dtype=torch.float32)
135
+ ops.qm_quantize_act(x_int8, scale, x_flat)
136
+ return x_int8, scale
137
+
138
+
139
+ def w4a8_linear(x: torch.Tensor, packed: torch.Tensor, scales: torch.Tensor,
140
+ zeros: torch.Tensor, group_size: int,
141
+ perm: Optional[torch.Tensor] = None) -> torch.Tensor:
142
+ """W4A8 forward: [..., K] bf16/f32 -> [..., N], dtype follows x."""
143
+ assert x.dtype in _OK_DTYPES, f"x must be bf16 or f32, got {x.dtype}"
144
+ orig = x.shape
145
+ x_flat = x.reshape(-1, orig[-1])
146
+ if perm is not None:
147
+ x_flat = x_flat[:, perm]
148
+ x_flat = x_flat.contiguous()
149
+ M = x_flat.shape[0]
150
+ N = packed.shape[0]
151
+ out = torch.empty((M, N), dtype=x.dtype)
152
+ if M < 16:
153
+ ops.qm_w4a8_gemv_fused(out, x_flat, packed, scales, zeros, group_size)
154
+ else:
155
+ q, sa = quantize_activation(x_flat)
156
+ ops.qm_w4a8_gemm(out, q, packed, scales, zeros, sa, group_size)
157
+ return out.view(*orig[:-1], N)
158
+
159
+
160
+ def w8a8_linear(x: torch.Tensor, w_int8: torch.Tensor,
161
+ scale_wt: torch.Tensor) -> torch.Tensor:
162
+ """W8A8 forward: per-token int8 activations x int8 weights, per-row scale."""
163
+ assert x.dtype in _OK_DTYPES
164
+ orig = x.shape
165
+ q, sa = quantize_activation(x.reshape(-1, orig[-1]))
166
+ N = w_int8.shape[0]
167
+ out = torch.empty((q.shape[0], N), dtype=x.dtype)
168
+ ops.qm_w8a8_gemm(out, q, w_int8, sa, scale_wt)
169
+ return out.view(*orig[:-1], N)
170
+
171
+
172
+ def fp16_gemv(x: torch.Tensor, w_f16: torch.Tensor) -> torch.Tensor:
173
+ """fp16-storage GEMV: f16 weights widened to f32 in registers."""
174
+ orig = x.shape
175
+ x_flat = x.reshape(-1, orig[-1]).to(torch.float32).contiguous()
176
+ N = w_f16.shape[0]
177
+ out = torch.empty((x_flat.shape[0], N), dtype=torch.float32)
178
+ ops.qm_fp16_gemv(out, x_flat, w_f16)
179
+ return out.view(*orig[:-1], N).to(x.dtype)
180
+
181
+
182
+ class QuantLinear(nn.Module):
183
+ """Inference-only W4A8 linear over the native packing."""
184
+
185
+ def __init__(self, packed, scales, zeros, group_size, perm=None, bias=None):
186
+ super().__init__()
187
+ self.register_buffer("packed", packed)
188
+ self.register_buffer("scales", scales)
189
+ self.register_buffer("zeros", zeros)
190
+ self.group_size = int(group_size)
191
+ if perm is not None:
192
+ self.register_buffer("perm", perm)
193
+ else:
194
+ self.perm = None
195
+ if bias is not None:
196
+ self.register_buffer("bias", bias)
197
+ else:
198
+ self.bias = None
199
+
200
+ @classmethod
201
+ def from_gptq_tensors(cls, qweight, qzeros, scales, g_idx=None, bias=None,
202
+ zero_offset=1):
203
+ packed, s, z, gs, perm = from_gptq(qweight, qzeros, scales, g_idx, zero_offset)
204
+ return cls(packed, s, z, gs, perm, bias)
205
+
206
+ @classmethod
207
+ def from_awq_tensors(cls, qweight, qzeros, scales, bias=None, zero_offset=0):
208
+ packed, s, z, gs, perm = from_awq(qweight, qzeros, scales, zero_offset)
209
+ return cls(packed, s, z, gs, perm, bias)
210
+
211
+ def forward(self, x: torch.Tensor) -> torch.Tensor:
212
+ y = w4a8_linear(x, self.packed, self.scales, self.zeros, self.group_size,
213
+ self.perm)
214
+ if self.bias is not None:
215
+ y = y + self.bias
216
+ return y
217
+
218
+
219
+ __all__ = [
220
+ "pack_w4",
221
+ "dequant_w4",
222
+ "from_gptq",
223
+ "from_awq",
224
+ "quantize_activation",
225
+ "w4a8_linear",
226
+ "w8a8_linear",
227
+ "fp16_gemv",
228
+ "QuantLinear",
229
+ ]
build/torch213-cxx11-cpu-x86_64-linux/_ops.py ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ import torch
2
+ from . import _quant_matmul_cpu_18a2909
3
+ ops = torch.ops._quant_matmul_cpu_18a2909
4
+
5
+ def add_op_namespace_prefix(op_name: str):
6
+ """
7
+ Prefix op by namespace.
8
+ """
9
+ return f"_quant_matmul_cpu_18a2909::{op_name}"
build/torch213-cxx11-cpu-x86_64-linux/_quant_matmul_cpu_18a2909.abi3.so ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:3c1e74f4c3e314bc8cfaf7d735b16b7176a13f20735d91b9b4843b264dc54cba
3
+ size 146952
build/torch213-cxx11-cpu-x86_64-linux/metadata.json ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "quant-matmul",
3
+ "id": "_quant_matmul_cpu_18a2909",
4
+ "version": 1,
5
+ "license": "Apache-2.0",
6
+ "python-depends": [],
7
+ "backend": {
8
+ "type": "cpu"
9
+ },
10
+ "digest": {
11
+ "algorithm": "sha256",
12
+ "files": {
13
+ "__init__.py": "FTTRodgwtEJbDPRdBoeZdVWC5sDL6EpzX8St+v6bUyI=",
14
+ "_ops.py": "7XG0r+IuC4ujAoIFN6lqK2qfTCKug4asMH3GvteKiuw=",
15
+ "_quant_matmul_cpu_18a2909.abi3.so": "PB509MPjFLyM+vfXNbFrcXahPyBzXZG5tIQ7Jk3FTLo=",
16
+ "quant_matmul/__init__.py": "DFYPlrhXwYjEqCl/8n0SmWGZV8NFml5DPhMjKfv98GY="
17
+ }
18
+ },
19
+ "provenance": {
20
+ "kernel-builder": {
21
+ "version": "0.17.0-dev0",
22
+ "sha": "19aaa6421e674e9fecc352bbae6eab81d19a6bf4",
23
+ "dirty": false
24
+ },
25
+ "kernel": {
26
+ "sha": "18a2909d5970949d8ec3915c4062d6c3c05466e8",
27
+ "dirty": false
28
+ }
29
+ }
30
+ }
build/torch213-cxx11-cpu-x86_64-linux/quant_matmul/__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")))