Uploaded using `kernel-builder`.
Browse files- build/torch211-cxx11-cpu-x86_64-linux/__init__.py +90 -0
- build/torch211-cxx11-cpu-x86_64-linux/_ops.py +9 -0
- build/torch211-cxx11-cpu-x86_64-linux/_spec_verify_cpu_9f08509.abi3.so +3 -0
- build/torch211-cxx11-cpu-x86_64-linux/metadata.json +30 -0
- build/torch211-cxx11-cpu-x86_64-linux/spec_verify/__init__.py +26 -0
- build/torch212-cxx11-cpu-x86_64-linux/__init__.py +90 -0
- build/torch212-cxx11-cpu-x86_64-linux/_ops.py +9 -0
- build/torch212-cxx11-cpu-x86_64-linux/_spec_verify_cpu_9f08509.abi3.so +3 -0
- build/torch212-cxx11-cpu-x86_64-linux/metadata.json +30 -0
- build/torch212-cxx11-cpu-x86_64-linux/spec_verify/__init__.py +26 -0
- build/torch213-cxx11-cpu-x86_64-linux/__init__.py +90 -0
- build/torch213-cxx11-cpu-x86_64-linux/_ops.py +9 -0
- build/torch213-cxx11-cpu-x86_64-linux/_spec_verify_cpu_9f08509.abi3.so +3 -0
- build/torch213-cxx11-cpu-x86_64-linux/metadata.json +30 -0
- build/torch213-cxx11-cpu-x86_64-linux/spec_verify/__init__.py +26 -0
build/torch211-cxx11-cpu-x86_64-linux/__init__.py
ADDED
|
@@ -0,0 +1,90 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""spec-verify: speculative-decoding verification ops for CPUs, aarch64-first.
|
| 2 |
+
|
| 3 |
+
A draft model proposes K tokens; the target verifies them in one [K+1, V]
|
| 4 |
+
forward (the batched-GEMM path where the companion linear kernels run
|
| 5 |
+
fastest). These ops turn that forward into an accepted prefix plus one
|
| 6 |
+
correction token: greedy (temperature 0) verification, or distribution-
|
| 7 |
+
preserving speculative sampling. Companions on the Hub: bitnet-cpu,
|
| 8 |
+
quant-matmul, gguf-gemv (linears), cpu-attn, decode-ops.
|
| 9 |
+
|
| 10 |
+
High-level API:
|
| 11 |
+
verify_greedy(target_probs, draft_tokens) -> (n_accepted, next_token)
|
| 12 |
+
accept(target_probs, draft_probs, draft_tokens, generator)
|
| 13 |
+
SpeculativeDecoder(draft_step, target_step, ...) orchestration loop
|
| 14 |
+
"""
|
| 15 |
+
from typing import Callable, List, Optional, Tuple
|
| 16 |
+
|
| 17 |
+
import torch
|
| 18 |
+
|
| 19 |
+
from ._ops import ops
|
| 20 |
+
|
| 21 |
+
|
| 22 |
+
def verify_greedy(target_probs: torch.Tensor,
|
| 23 |
+
draft_tokens: torch.Tensor) -> Tuple[int, int]:
|
| 24 |
+
"""Temperature-0 verify. target_probs [K+1, V] (probs or logits; only the
|
| 25 |
+
argmax is used), draft_tokens [K] int64. Returns (n_accepted, next_token):
|
| 26 |
+
keep draft_tokens[:n_accepted] and append next_token."""
|
| 27 |
+
tp = target_probs.to(torch.float32).contiguous()
|
| 28 |
+
dt = draft_tokens.to(torch.int64).contiguous()
|
| 29 |
+
n, tok = ops.sv_verify_greedy(tp, dt)
|
| 30 |
+
return int(n), int(tok)
|
| 31 |
+
|
| 32 |
+
|
| 33 |
+
def accept(target_probs: torch.Tensor, draft_probs: torch.Tensor,
|
| 34 |
+
draft_tokens: torch.Tensor,
|
| 35 |
+
generator: Optional[torch.Generator] = None) -> Tuple[int, int]:
|
| 36 |
+
"""Distribution-preserving speculative sampling.
|
| 37 |
+
|
| 38 |
+
target_probs [K+1, V] and draft_probs [K, V] must be post-warp
|
| 39 |
+
probability distributions warped identically (the caller's contract).
|
| 40 |
+
Returns (n_accepted, next_token), deterministic given the generator.
|
| 41 |
+
"""
|
| 42 |
+
K = int(draft_tokens.numel())
|
| 43 |
+
ra = torch.rand(K, generator=generator, dtype=torch.float32)
|
| 44 |
+
rr = float(torch.rand(1, generator=generator).item())
|
| 45 |
+
tp = target_probs.to(torch.float32).contiguous()
|
| 46 |
+
dp = draft_probs.to(torch.float32).contiguous()
|
| 47 |
+
dt = draft_tokens.to(torch.int64).contiguous()
|
| 48 |
+
n, tok = ops.sv_accept(tp, dp, dt, ra.contiguous(), rr)
|
| 49 |
+
return int(n), int(tok)
|
| 50 |
+
|
| 51 |
+
|
| 52 |
+
class SpeculativeDecoder:
|
| 53 |
+
"""Draft/verify loop over user-supplied step callbacks.
|
| 54 |
+
|
| 55 |
+
draft_step(prefix, k) -> (tokens [k] int64, probs [k, V] or None)
|
| 56 |
+
target_step(prefix, proposed [k]) -> target_probs [k+1, V]
|
| 57 |
+
|
| 58 |
+
With temperature 0 (greedy) draft probs are unused; otherwise the caller
|
| 59 |
+
returns post-warp draft probabilities and the target_probs must carry the
|
| 60 |
+
same warping for the sampling to preserve the target distribution.
|
| 61 |
+
"""
|
| 62 |
+
|
| 63 |
+
def __init__(self, draft_step: Callable, target_step: Callable,
|
| 64 |
+
k: int = 4, greedy: bool = True,
|
| 65 |
+
generator: Optional[torch.Generator] = None):
|
| 66 |
+
self.draft_step = draft_step
|
| 67 |
+
self.target_step = target_step
|
| 68 |
+
self.k = k
|
| 69 |
+
self.greedy = greedy
|
| 70 |
+
self.generator = generator
|
| 71 |
+
|
| 72 |
+
def step(self, prefix: List[int]) -> Tuple[List[int], int]:
|
| 73 |
+
"""One speculative round: returns (accepted_tokens, n_target_calls=1)."""
|
| 74 |
+
proposed, dprobs = self.draft_step(prefix, self.k)
|
| 75 |
+
tprobs = self.target_step(prefix, proposed)
|
| 76 |
+
if self.greedy:
|
| 77 |
+
n, tok = verify_greedy(tprobs, proposed)
|
| 78 |
+
else:
|
| 79 |
+
n, tok = accept(tprobs, dprobs, proposed, self.generator)
|
| 80 |
+
return [int(proposed[i]) for i in range(n)] + [tok], 1
|
| 81 |
+
|
| 82 |
+
def generate(self, prefix: List[int], max_new: int) -> List[int]:
|
| 83 |
+
out = list(prefix)
|
| 84 |
+
while len(out) - len(prefix) < max_new:
|
| 85 |
+
accepted, _ = self.step(out)
|
| 86 |
+
out.extend(accepted)
|
| 87 |
+
return out[: len(prefix) + max_new]
|
| 88 |
+
|
| 89 |
+
|
| 90 |
+
__all__ = ["verify_greedy", "accept", "SpeculativeDecoder"]
|
build/torch211-cxx11-cpu-x86_64-linux/_ops.py
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import torch
|
| 2 |
+
from . import _spec_verify_cpu_9f08509
|
| 3 |
+
ops = torch.ops._spec_verify_cpu_9f08509
|
| 4 |
+
|
| 5 |
+
def add_op_namespace_prefix(op_name: str):
|
| 6 |
+
"""
|
| 7 |
+
Prefix op by namespace.
|
| 8 |
+
"""
|
| 9 |
+
return f"_spec_verify_cpu_9f08509::{op_name}"
|
build/torch211-cxx11-cpu-x86_64-linux/_spec_verify_cpu_9f08509.abi3.so
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:9e6eb6a1c073ea8823320019ad5ba960680f142ea9fa581afd2b7cd3c39912a2
|
| 3 |
+
size 70400
|
build/torch211-cxx11-cpu-x86_64-linux/metadata.json
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"name": "spec-verify",
|
| 3 |
+
"id": "_spec_verify_cpu_9f08509",
|
| 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": "UlLRZztEids73FkPtfMh14gPWORZUqSZ6p1k/bas1pI=",
|
| 14 |
+
"_ops.py": "Cz9lzcNnPDNcX6cbRzRg5c5NfXKMaGHpqCA0XFdtthE=",
|
| 15 |
+
"_spec_verify_cpu_9f08509.abi3.so": "nm62ocBz6ogjMgAZrVupYGgPFC6p+lga/St808OZEqI=",
|
| 16 |
+
"spec_verify/__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": "9f085096c7c6f9326be6bdb489d64f8ae81278a9",
|
| 27 |
+
"dirty": false
|
| 28 |
+
}
|
| 29 |
+
}
|
| 30 |
+
}
|
build/torch211-cxx11-cpu-x86_64-linux/spec_verify/__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,90 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""spec-verify: speculative-decoding verification ops for CPUs, aarch64-first.
|
| 2 |
+
|
| 3 |
+
A draft model proposes K tokens; the target verifies them in one [K+1, V]
|
| 4 |
+
forward (the batched-GEMM path where the companion linear kernels run
|
| 5 |
+
fastest). These ops turn that forward into an accepted prefix plus one
|
| 6 |
+
correction token: greedy (temperature 0) verification, or distribution-
|
| 7 |
+
preserving speculative sampling. Companions on the Hub: bitnet-cpu,
|
| 8 |
+
quant-matmul, gguf-gemv (linears), cpu-attn, decode-ops.
|
| 9 |
+
|
| 10 |
+
High-level API:
|
| 11 |
+
verify_greedy(target_probs, draft_tokens) -> (n_accepted, next_token)
|
| 12 |
+
accept(target_probs, draft_probs, draft_tokens, generator)
|
| 13 |
+
SpeculativeDecoder(draft_step, target_step, ...) orchestration loop
|
| 14 |
+
"""
|
| 15 |
+
from typing import Callable, List, Optional, Tuple
|
| 16 |
+
|
| 17 |
+
import torch
|
| 18 |
+
|
| 19 |
+
from ._ops import ops
|
| 20 |
+
|
| 21 |
+
|
| 22 |
+
def verify_greedy(target_probs: torch.Tensor,
|
| 23 |
+
draft_tokens: torch.Tensor) -> Tuple[int, int]:
|
| 24 |
+
"""Temperature-0 verify. target_probs [K+1, V] (probs or logits; only the
|
| 25 |
+
argmax is used), draft_tokens [K] int64. Returns (n_accepted, next_token):
|
| 26 |
+
keep draft_tokens[:n_accepted] and append next_token."""
|
| 27 |
+
tp = target_probs.to(torch.float32).contiguous()
|
| 28 |
+
dt = draft_tokens.to(torch.int64).contiguous()
|
| 29 |
+
n, tok = ops.sv_verify_greedy(tp, dt)
|
| 30 |
+
return int(n), int(tok)
|
| 31 |
+
|
| 32 |
+
|
| 33 |
+
def accept(target_probs: torch.Tensor, draft_probs: torch.Tensor,
|
| 34 |
+
draft_tokens: torch.Tensor,
|
| 35 |
+
generator: Optional[torch.Generator] = None) -> Tuple[int, int]:
|
| 36 |
+
"""Distribution-preserving speculative sampling.
|
| 37 |
+
|
| 38 |
+
target_probs [K+1, V] and draft_probs [K, V] must be post-warp
|
| 39 |
+
probability distributions warped identically (the caller's contract).
|
| 40 |
+
Returns (n_accepted, next_token), deterministic given the generator.
|
| 41 |
+
"""
|
| 42 |
+
K = int(draft_tokens.numel())
|
| 43 |
+
ra = torch.rand(K, generator=generator, dtype=torch.float32)
|
| 44 |
+
rr = float(torch.rand(1, generator=generator).item())
|
| 45 |
+
tp = target_probs.to(torch.float32).contiguous()
|
| 46 |
+
dp = draft_probs.to(torch.float32).contiguous()
|
| 47 |
+
dt = draft_tokens.to(torch.int64).contiguous()
|
| 48 |
+
n, tok = ops.sv_accept(tp, dp, dt, ra.contiguous(), rr)
|
| 49 |
+
return int(n), int(tok)
|
| 50 |
+
|
| 51 |
+
|
| 52 |
+
class SpeculativeDecoder:
|
| 53 |
+
"""Draft/verify loop over user-supplied step callbacks.
|
| 54 |
+
|
| 55 |
+
draft_step(prefix, k) -> (tokens [k] int64, probs [k, V] or None)
|
| 56 |
+
target_step(prefix, proposed [k]) -> target_probs [k+1, V]
|
| 57 |
+
|
| 58 |
+
With temperature 0 (greedy) draft probs are unused; otherwise the caller
|
| 59 |
+
returns post-warp draft probabilities and the target_probs must carry the
|
| 60 |
+
same warping for the sampling to preserve the target distribution.
|
| 61 |
+
"""
|
| 62 |
+
|
| 63 |
+
def __init__(self, draft_step: Callable, target_step: Callable,
|
| 64 |
+
k: int = 4, greedy: bool = True,
|
| 65 |
+
generator: Optional[torch.Generator] = None):
|
| 66 |
+
self.draft_step = draft_step
|
| 67 |
+
self.target_step = target_step
|
| 68 |
+
self.k = k
|
| 69 |
+
self.greedy = greedy
|
| 70 |
+
self.generator = generator
|
| 71 |
+
|
| 72 |
+
def step(self, prefix: List[int]) -> Tuple[List[int], int]:
|
| 73 |
+
"""One speculative round: returns (accepted_tokens, n_target_calls=1)."""
|
| 74 |
+
proposed, dprobs = self.draft_step(prefix, self.k)
|
| 75 |
+
tprobs = self.target_step(prefix, proposed)
|
| 76 |
+
if self.greedy:
|
| 77 |
+
n, tok = verify_greedy(tprobs, proposed)
|
| 78 |
+
else:
|
| 79 |
+
n, tok = accept(tprobs, dprobs, proposed, self.generator)
|
| 80 |
+
return [int(proposed[i]) for i in range(n)] + [tok], 1
|
| 81 |
+
|
| 82 |
+
def generate(self, prefix: List[int], max_new: int) -> List[int]:
|
| 83 |
+
out = list(prefix)
|
| 84 |
+
while len(out) - len(prefix) < max_new:
|
| 85 |
+
accepted, _ = self.step(out)
|
| 86 |
+
out.extend(accepted)
|
| 87 |
+
return out[: len(prefix) + max_new]
|
| 88 |
+
|
| 89 |
+
|
| 90 |
+
__all__ = ["verify_greedy", "accept", "SpeculativeDecoder"]
|
build/torch212-cxx11-cpu-x86_64-linux/_ops.py
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import torch
|
| 2 |
+
from . import _spec_verify_cpu_9f08509
|
| 3 |
+
ops = torch.ops._spec_verify_cpu_9f08509
|
| 4 |
+
|
| 5 |
+
def add_op_namespace_prefix(op_name: str):
|
| 6 |
+
"""
|
| 7 |
+
Prefix op by namespace.
|
| 8 |
+
"""
|
| 9 |
+
return f"_spec_verify_cpu_9f08509::{op_name}"
|
build/torch212-cxx11-cpu-x86_64-linux/_spec_verify_cpu_9f08509.abi3.so
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:c71736f80d80a059cbb3cf85edd844500e50cebdcd53a191b05405701969622b
|
| 3 |
+
size 70096
|
build/torch212-cxx11-cpu-x86_64-linux/metadata.json
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"name": "spec-verify",
|
| 3 |
+
"id": "_spec_verify_cpu_9f08509",
|
| 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": "UlLRZztEids73FkPtfMh14gPWORZUqSZ6p1k/bas1pI=",
|
| 14 |
+
"_ops.py": "Cz9lzcNnPDNcX6cbRzRg5c5NfXKMaGHpqCA0XFdtthE=",
|
| 15 |
+
"_spec_verify_cpu_9f08509.abi3.so": "xxc2+A2AoFnLs8+F7dhEUA5Qzr3NU6GRsFQFcBlpYis=",
|
| 16 |
+
"spec_verify/__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": "9f085096c7c6f9326be6bdb489d64f8ae81278a9",
|
| 27 |
+
"dirty": false
|
| 28 |
+
}
|
| 29 |
+
}
|
| 30 |
+
}
|
build/torch212-cxx11-cpu-x86_64-linux/spec_verify/__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,90 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""spec-verify: speculative-decoding verification ops for CPUs, aarch64-first.
|
| 2 |
+
|
| 3 |
+
A draft model proposes K tokens; the target verifies them in one [K+1, V]
|
| 4 |
+
forward (the batched-GEMM path where the companion linear kernels run
|
| 5 |
+
fastest). These ops turn that forward into an accepted prefix plus one
|
| 6 |
+
correction token: greedy (temperature 0) verification, or distribution-
|
| 7 |
+
preserving speculative sampling. Companions on the Hub: bitnet-cpu,
|
| 8 |
+
quant-matmul, gguf-gemv (linears), cpu-attn, decode-ops.
|
| 9 |
+
|
| 10 |
+
High-level API:
|
| 11 |
+
verify_greedy(target_probs, draft_tokens) -> (n_accepted, next_token)
|
| 12 |
+
accept(target_probs, draft_probs, draft_tokens, generator)
|
| 13 |
+
SpeculativeDecoder(draft_step, target_step, ...) orchestration loop
|
| 14 |
+
"""
|
| 15 |
+
from typing import Callable, List, Optional, Tuple
|
| 16 |
+
|
| 17 |
+
import torch
|
| 18 |
+
|
| 19 |
+
from ._ops import ops
|
| 20 |
+
|
| 21 |
+
|
| 22 |
+
def verify_greedy(target_probs: torch.Tensor,
|
| 23 |
+
draft_tokens: torch.Tensor) -> Tuple[int, int]:
|
| 24 |
+
"""Temperature-0 verify. target_probs [K+1, V] (probs or logits; only the
|
| 25 |
+
argmax is used), draft_tokens [K] int64. Returns (n_accepted, next_token):
|
| 26 |
+
keep draft_tokens[:n_accepted] and append next_token."""
|
| 27 |
+
tp = target_probs.to(torch.float32).contiguous()
|
| 28 |
+
dt = draft_tokens.to(torch.int64).contiguous()
|
| 29 |
+
n, tok = ops.sv_verify_greedy(tp, dt)
|
| 30 |
+
return int(n), int(tok)
|
| 31 |
+
|
| 32 |
+
|
| 33 |
+
def accept(target_probs: torch.Tensor, draft_probs: torch.Tensor,
|
| 34 |
+
draft_tokens: torch.Tensor,
|
| 35 |
+
generator: Optional[torch.Generator] = None) -> Tuple[int, int]:
|
| 36 |
+
"""Distribution-preserving speculative sampling.
|
| 37 |
+
|
| 38 |
+
target_probs [K+1, V] and draft_probs [K, V] must be post-warp
|
| 39 |
+
probability distributions warped identically (the caller's contract).
|
| 40 |
+
Returns (n_accepted, next_token), deterministic given the generator.
|
| 41 |
+
"""
|
| 42 |
+
K = int(draft_tokens.numel())
|
| 43 |
+
ra = torch.rand(K, generator=generator, dtype=torch.float32)
|
| 44 |
+
rr = float(torch.rand(1, generator=generator).item())
|
| 45 |
+
tp = target_probs.to(torch.float32).contiguous()
|
| 46 |
+
dp = draft_probs.to(torch.float32).contiguous()
|
| 47 |
+
dt = draft_tokens.to(torch.int64).contiguous()
|
| 48 |
+
n, tok = ops.sv_accept(tp, dp, dt, ra.contiguous(), rr)
|
| 49 |
+
return int(n), int(tok)
|
| 50 |
+
|
| 51 |
+
|
| 52 |
+
class SpeculativeDecoder:
|
| 53 |
+
"""Draft/verify loop over user-supplied step callbacks.
|
| 54 |
+
|
| 55 |
+
draft_step(prefix, k) -> (tokens [k] int64, probs [k, V] or None)
|
| 56 |
+
target_step(prefix, proposed [k]) -> target_probs [k+1, V]
|
| 57 |
+
|
| 58 |
+
With temperature 0 (greedy) draft probs are unused; otherwise the caller
|
| 59 |
+
returns post-warp draft probabilities and the target_probs must carry the
|
| 60 |
+
same warping for the sampling to preserve the target distribution.
|
| 61 |
+
"""
|
| 62 |
+
|
| 63 |
+
def __init__(self, draft_step: Callable, target_step: Callable,
|
| 64 |
+
k: int = 4, greedy: bool = True,
|
| 65 |
+
generator: Optional[torch.Generator] = None):
|
| 66 |
+
self.draft_step = draft_step
|
| 67 |
+
self.target_step = target_step
|
| 68 |
+
self.k = k
|
| 69 |
+
self.greedy = greedy
|
| 70 |
+
self.generator = generator
|
| 71 |
+
|
| 72 |
+
def step(self, prefix: List[int]) -> Tuple[List[int], int]:
|
| 73 |
+
"""One speculative round: returns (accepted_tokens, n_target_calls=1)."""
|
| 74 |
+
proposed, dprobs = self.draft_step(prefix, self.k)
|
| 75 |
+
tprobs = self.target_step(prefix, proposed)
|
| 76 |
+
if self.greedy:
|
| 77 |
+
n, tok = verify_greedy(tprobs, proposed)
|
| 78 |
+
else:
|
| 79 |
+
n, tok = accept(tprobs, dprobs, proposed, self.generator)
|
| 80 |
+
return [int(proposed[i]) for i in range(n)] + [tok], 1
|
| 81 |
+
|
| 82 |
+
def generate(self, prefix: List[int], max_new: int) -> List[int]:
|
| 83 |
+
out = list(prefix)
|
| 84 |
+
while len(out) - len(prefix) < max_new:
|
| 85 |
+
accepted, _ = self.step(out)
|
| 86 |
+
out.extend(accepted)
|
| 87 |
+
return out[: len(prefix) + max_new]
|
| 88 |
+
|
| 89 |
+
|
| 90 |
+
__all__ = ["verify_greedy", "accept", "SpeculativeDecoder"]
|
build/torch213-cxx11-cpu-x86_64-linux/_ops.py
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import torch
|
| 2 |
+
from . import _spec_verify_cpu_9f08509
|
| 3 |
+
ops = torch.ops._spec_verify_cpu_9f08509
|
| 4 |
+
|
| 5 |
+
def add_op_namespace_prefix(op_name: str):
|
| 6 |
+
"""
|
| 7 |
+
Prefix op by namespace.
|
| 8 |
+
"""
|
| 9 |
+
return f"_spec_verify_cpu_9f08509::{op_name}"
|
build/torch213-cxx11-cpu-x86_64-linux/_spec_verify_cpu_9f08509.abi3.so
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:0c1a24ef1dd8b94ee1901d0b42d2ff727193ac535cac505fc5fbe5529802bf41
|
| 3 |
+
size 70096
|
build/torch213-cxx11-cpu-x86_64-linux/metadata.json
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"name": "spec-verify",
|
| 3 |
+
"id": "_spec_verify_cpu_9f08509",
|
| 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": "UlLRZztEids73FkPtfMh14gPWORZUqSZ6p1k/bas1pI=",
|
| 14 |
+
"_ops.py": "Cz9lzcNnPDNcX6cbRzRg5c5NfXKMaGHpqCA0XFdtthE=",
|
| 15 |
+
"_spec_verify_cpu_9f08509.abi3.so": "DBok7x3YuU7hkB0LQtL/cnGTrFNcrFBfxfvlUpgCv0E=",
|
| 16 |
+
"spec_verify/__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": "9f085096c7c6f9326be6bdb489d64f8ae81278a9",
|
| 27 |
+
"dirty": false
|
| 28 |
+
}
|
| 29 |
+
}
|
| 30 |
+
}
|
build/torch213-cxx11-cpu-x86_64-linux/spec_verify/__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")))
|