GGUF kernels: dequantize + fused gemv over packed blocks, 9 CUDA variants
Browse filesThis view is limited to 50 files because it contains too many changes. See raw diff
- .gitattributes +9 -0
- .pytest_cache/.gitignore +2 -0
- .pytest_cache/CACHEDIR.TAG +4 -0
- .pytest_cache/README.md +8 -0
- .pytest_cache/v/cache/lastfailed +1 -0
- .pytest_cache/v/cache/nodeids +23 -0
- README.md +62 -0
- build.toml +74 -0
- build/torch210-cxx11-cu126-x86_64-linux/__init__.py +55 -0
- build/torch210-cxx11-cu126-x86_64-linux/_gguf_kernels_20260805124229.abi3.so +3 -0
- build/torch210-cxx11-cu126-x86_64-linux/_ops.py +9 -0
- build/torch210-cxx11-cu126-x86_64-linux/gguf_kernels/__init__.py +26 -0
- build/torch210-cxx11-cu126-x86_64-linux/metadata.json +4 -0
- build/torch210-cxx11-cu128-x86_64-linux/__init__.py +55 -0
- build/torch210-cxx11-cu128-x86_64-linux/_gguf_kernels_20260805124229.abi3.so +3 -0
- build/torch210-cxx11-cu128-x86_64-linux/_ops.py +9 -0
- build/torch210-cxx11-cu128-x86_64-linux/gguf_kernels/__init__.py +26 -0
- build/torch210-cxx11-cu128-x86_64-linux/metadata.json +4 -0
- build/torch210-cxx11-cu130-x86_64-linux/__init__.py +55 -0
- build/torch210-cxx11-cu130-x86_64-linux/_gguf_kernels_20260805124229.abi3.so +3 -0
- build/torch210-cxx11-cu130-x86_64-linux/_ops.py +9 -0
- build/torch210-cxx11-cu130-x86_64-linux/gguf_kernels/__init__.py +26 -0
- build/torch210-cxx11-cu130-x86_64-linux/metadata.json +4 -0
- build/torch28-cxx11-cu126-x86_64-linux/__init__.py +55 -0
- build/torch28-cxx11-cu126-x86_64-linux/_gguf_kernels_20260805124229.abi3.so +3 -0
- build/torch28-cxx11-cu126-x86_64-linux/_ops.py +9 -0
- build/torch28-cxx11-cu126-x86_64-linux/gguf_kernels/__init__.py +26 -0
- build/torch28-cxx11-cu126-x86_64-linux/metadata.json +4 -0
- build/torch28-cxx11-cu128-x86_64-linux/__init__.py +55 -0
- build/torch28-cxx11-cu128-x86_64-linux/_gguf_kernels_20260805124229.abi3.so +3 -0
- build/torch28-cxx11-cu128-x86_64-linux/_ops.py +9 -0
- build/torch28-cxx11-cu128-x86_64-linux/gguf_kernels/__init__.py +26 -0
- build/torch28-cxx11-cu128-x86_64-linux/metadata.json +4 -0
- build/torch28-cxx11-cu129-x86_64-linux/__init__.py +55 -0
- build/torch28-cxx11-cu129-x86_64-linux/_gguf_kernels_20260805124229.abi3.so +3 -0
- build/torch28-cxx11-cu129-x86_64-linux/_ops.py +9 -0
- build/torch28-cxx11-cu129-x86_64-linux/gguf_kernels/__init__.py +26 -0
- build/torch28-cxx11-cu129-x86_64-linux/metadata.json +4 -0
- build/torch29-cxx11-cu126-x86_64-linux/__init__.py +55 -0
- build/torch29-cxx11-cu126-x86_64-linux/_gguf_kernels_20260805124229.abi3.so +3 -0
- build/torch29-cxx11-cu126-x86_64-linux/_ops.py +9 -0
- build/torch29-cxx11-cu126-x86_64-linux/gguf_kernels/__init__.py +26 -0
- build/torch29-cxx11-cu126-x86_64-linux/metadata.json +4 -0
- build/torch29-cxx11-cu128-x86_64-linux/__init__.py +55 -0
- build/torch29-cxx11-cu128-x86_64-linux/_gguf_kernels_20260805124229.abi3.so +3 -0
- build/torch29-cxx11-cu128-x86_64-linux/_ops.py +9 -0
- build/torch29-cxx11-cu128-x86_64-linux/gguf_kernels/__init__.py +26 -0
- build/torch29-cxx11-cu128-x86_64-linux/metadata.json +4 -0
- build/torch29-cxx11-cu130-x86_64-linux/__init__.py +55 -0
- build/torch29-cxx11-cu130-x86_64-linux/_gguf_kernels_20260805124229.abi3.so +3 -0
.gitattributes
CHANGED
|
@@ -33,3 +33,12 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
|
|
| 33 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
| 34 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
| 35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 33 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
| 34 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
| 35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
| 36 |
+
build/torch210-cxx11-cu126-x86_64-linux/_gguf_kernels_20260805124229.abi3.so filter=lfs diff=lfs merge=lfs -text
|
| 37 |
+
build/torch210-cxx11-cu128-x86_64-linux/_gguf_kernels_20260805124229.abi3.so filter=lfs diff=lfs merge=lfs -text
|
| 38 |
+
build/torch210-cxx11-cu130-x86_64-linux/_gguf_kernels_20260805124229.abi3.so filter=lfs diff=lfs merge=lfs -text
|
| 39 |
+
build/torch28-cxx11-cu126-x86_64-linux/_gguf_kernels_20260805124229.abi3.so filter=lfs diff=lfs merge=lfs -text
|
| 40 |
+
build/torch28-cxx11-cu128-x86_64-linux/_gguf_kernels_20260805124229.abi3.so filter=lfs diff=lfs merge=lfs -text
|
| 41 |
+
build/torch28-cxx11-cu129-x86_64-linux/_gguf_kernels_20260805124229.abi3.so filter=lfs diff=lfs merge=lfs -text
|
| 42 |
+
build/torch29-cxx11-cu126-x86_64-linux/_gguf_kernels_20260805124229.abi3.so filter=lfs diff=lfs merge=lfs -text
|
| 43 |
+
build/torch29-cxx11-cu128-x86_64-linux/_gguf_kernels_20260805124229.abi3.so filter=lfs diff=lfs merge=lfs -text
|
| 44 |
+
build/torch29-cxx11-cu130-x86_64-linux/_gguf_kernels_20260805124229.abi3.so filter=lfs diff=lfs merge=lfs -text
|
.pytest_cache/.gitignore
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Created by pytest automatically.
|
| 2 |
+
*
|
.pytest_cache/CACHEDIR.TAG
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
Signature: 8a477f597d28d172789f06886806bc55
|
| 2 |
+
# This file is a cache directory tag created by pytest.
|
| 3 |
+
# For information about cache directory tags, see:
|
| 4 |
+
# https://bford.info/cachedir/spec.html
|
.pytest_cache/README.md
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# pytest cache directory #
|
| 2 |
+
|
| 3 |
+
This directory contains data from the pytest's cache plugin,
|
| 4 |
+
which provides the `--lf` and `--ff` options, as well as the `cache` fixture.
|
| 5 |
+
|
| 6 |
+
**Do not** commit this to version control.
|
| 7 |
+
|
| 8 |
+
See [the docs](https://docs.pytest.org/en/stable/how-to/cache.html) for more information.
|
.pytest_cache/v/cache/lastfailed
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
{}
|
.pytest_cache/v/cache/nodeids
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
[
|
| 2 |
+
"tests/test_gguf_kernels.py::test_dequantize_matches_reference[dtype0-Q4_K]",
|
| 3 |
+
"tests/test_gguf_kernels.py::test_dequantize_matches_reference[dtype0-Q5_K]",
|
| 4 |
+
"tests/test_gguf_kernels.py::test_dequantize_matches_reference[dtype0-Q6_K]",
|
| 5 |
+
"tests/test_gguf_kernels.py::test_dequantize_matches_reference[dtype0-Q8_0]",
|
| 6 |
+
"tests/test_gguf_kernels.py::test_dequantize_matches_reference[dtype1-Q4_K]",
|
| 7 |
+
"tests/test_gguf_kernels.py::test_dequantize_matches_reference[dtype1-Q5_K]",
|
| 8 |
+
"tests/test_gguf_kernels.py::test_dequantize_matches_reference[dtype1-Q6_K]",
|
| 9 |
+
"tests/test_gguf_kernels.py::test_dequantize_matches_reference[dtype1-Q8_0]",
|
| 10 |
+
"tests/test_gguf_kernels.py::test_dequantize_matches_reference[dtype2-Q4_K]",
|
| 11 |
+
"tests/test_gguf_kernels.py::test_dequantize_matches_reference[dtype2-Q5_K]",
|
| 12 |
+
"tests/test_gguf_kernels.py::test_dequantize_matches_reference[dtype2-Q6_K]",
|
| 13 |
+
"tests/test_gguf_kernels.py::test_dequantize_matches_reference[dtype2-Q8_0]",
|
| 14 |
+
"tests/test_gguf_kernels.py::test_gemv_is_compileable",
|
| 15 |
+
"tests/test_gguf_kernels.py::test_mul_mat_vec_matches_matmul[1-Q4_K]",
|
| 16 |
+
"tests/test_gguf_kernels.py::test_mul_mat_vec_matches_matmul[1-Q5_K]",
|
| 17 |
+
"tests/test_gguf_kernels.py::test_mul_mat_vec_matches_matmul[1-Q6_K]",
|
| 18 |
+
"tests/test_gguf_kernels.py::test_mul_mat_vec_matches_matmul[1-Q8_0]",
|
| 19 |
+
"tests/test_gguf_kernels.py::test_mul_mat_vec_matches_matmul[8-Q4_K]",
|
| 20 |
+
"tests/test_gguf_kernels.py::test_mul_mat_vec_matches_matmul[8-Q5_K]",
|
| 21 |
+
"tests/test_gguf_kernels.py::test_mul_mat_vec_matches_matmul[8-Q6_K]",
|
| 22 |
+
"tests/test_gguf_kernels.py::test_mul_mat_vec_matches_matmul[8-Q8_0]"
|
| 23 |
+
]
|
README.md
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
---
|
| 2 |
+
license: mit
|
| 3 |
+
tags:
|
| 4 |
+
- kernel
|
| 5 |
+
- gguf
|
| 6 |
+
- quantization
|
| 7 |
+
---
|
| 8 |
+
|
| 9 |
+
# GGUF kernels
|
| 10 |
+
|
| 11 |
+
Compute directly on the packed blocks of a GGUF checkpoint.
|
| 12 |
+
|
| 13 |
+
A GGUF weight is stored as blocks of 32 or 256 values that share a scale. These kernels read that
|
| 14 |
+
layout as it is, so a quantized model runs without ever materializing a dense copy of its weights —
|
| 15 |
+
which is where the memory saving comes from. A 4B model at Q4_K_M stays at 3.1 GB instead of the
|
| 16 |
+
8.4 GB it would take unpacked.
|
| 17 |
+
|
| 18 |
+
Ported from [llama.cpp](https://github.com/ggml-org/llama.cpp)'s `ggml-cuda`. `vendor/UPSTREAM`
|
| 19 |
+
pins the revision the sources come from; `vendor.py` refreshes them.
|
| 20 |
+
|
| 21 |
+
## Usage
|
| 22 |
+
|
| 23 |
+
```python
|
| 24 |
+
import torch
|
| 25 |
+
from kernels import get_kernel
|
| 26 |
+
|
| 27 |
+
gguf_kernels = get_kernel("marcsun13/gguf-kernels")
|
| 28 |
+
|
| 29 |
+
# `blocks` is a GGUF weight exactly as stored: (out_features, bytes_per_row) uint8
|
| 30 |
+
out = gguf_kernels.mul_mat_vec(blocks, x, ggml_type=12, out_features=4096) # x @ blocks.T
|
| 31 |
+
dense = gguf_kernels.dequantize(blocks, ggml_type=12, rows=4096, cols=2560, dtype=torch.bfloat16)
|
| 32 |
+
```
|
| 33 |
+
|
| 34 |
+
| | |
|
| 35 |
+
| --- | --- |
|
| 36 |
+
| `mul_mat_vec(blocks, x, ggml_type, out_features)` | Fused dequantize-gemv, for `x` of at most `MAX_GEMV_ROWS` rows (decode). Returns f32 whatever `x` was: the kernel writes an f32 destination, and casting at the call site lets the cast fuse into the consumer. |
|
| 37 |
+
| `dequantize(blocks, ggml_type, rows, cols, dtype)` | Blocks to values, in `dtype` directly. For more rows than the gemv handles (prefill), unpack and use an ordinary matmul. |
|
| 38 |
+
| `MAX_GEMV_ROWS` | Upstream's `MMVQ_MAX_BATCH_SIZE`. Beyond this the gemv has no implementation. |
|
| 39 |
+
| `GEMV_TYPES` | The ggml type ids `mul_mat_vec` implements. `dequantize` covers more, so check this before choosing the fused path. |
|
| 40 |
+
|
| 41 |
+
Both ops carry `register_fake` implementations, so they trace under `torch.compile` instead of
|
| 42 |
+
breaking the graph — which matters, since a break at every quantized linear costs more than the
|
| 43 |
+
kernels save.
|
| 44 |
+
|
| 45 |
+
## Backends
|
| 46 |
+
|
| 47 |
+
CUDA today. The ops are named for what they do rather than for a backend: the schema is declared
|
| 48 |
+
once in `torch-ext/torch_binding.cpp` and each backend registers its own implementation of it, so
|
| 49 |
+
adding Metal means adding a `[kernel.*]` section and a source directory — no change to the schema or
|
| 50 |
+
to the Python API, and callers dispatch on the tensor's device as usual.
|
| 51 |
+
|
| 52 |
+
`mmq` (quantized gemm) and `mmf` (dense gemm) are deliberately not ported: both take a
|
| 53 |
+
`ggml_backend_cuda_context` for their pool allocator, which would pull in the whole ggml backend.
|
| 54 |
+
Above the gemv's row limit, unpacking and using cuBLAS measures at parity with llama.cpp anyway.
|
| 55 |
+
|
| 56 |
+
## Building
|
| 57 |
+
|
| 58 |
+
```bash
|
| 59 |
+
nix run .#build-and-copy -L # every variant, into build/
|
| 60 |
+
nix build .#ci # just this system's variant
|
| 61 |
+
pytest tests/ # against a built variant on PYTHONPATH
|
| 62 |
+
```
|
build.toml
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# One backend per `[kernel.*]` section, all implementing the same two entry points declared in
|
| 2 |
+
# torch-ext/torch_binding.h. Adding Metal means adding a section and a `gguf_metal/` directory —
|
| 3 |
+
# no change to the bindings' schema or to the Python API.
|
| 4 |
+
#
|
| 5 |
+
# `vendor/` is a pinned subset of llama.cpp (revision in vendor/UPSTREAM); refresh it with
|
| 6 |
+
# `python vendor.py --rev <sha>`.
|
| 7 |
+
|
| 8 |
+
[general]
|
| 9 |
+
name = "gguf-kernels"
|
| 10 |
+
version = 1
|
| 11 |
+
backends = ["cuda"]
|
| 12 |
+
|
| 13 |
+
[torch]
|
| 14 |
+
src = [
|
| 15 |
+
"torch-ext/torch_binding.cpp",
|
| 16 |
+
"torch-ext/torch_binding.h",
|
| 17 |
+
]
|
| 18 |
+
|
| 19 |
+
[kernel.gguf_cuda]
|
| 20 |
+
backend = "cuda"
|
| 21 |
+
depends = ["torch"]
|
| 22 |
+
cuda-capabilities = ["7.5", "8.0", "8.6", "8.9", "9.0", "10.0", "12.0"]
|
| 23 |
+
include = ["gguf_cuda", "torch-ext", "vendor/include", "vendor/src", "vendor/src/ggml-cuda"]
|
| 24 |
+
src = [
|
| 25 |
+
"gguf_cuda/gguf_cuda.cu",
|
| 26 |
+
"gguf_cuda/ggml_dispatch.cu",
|
| 27 |
+
"gguf_cuda/ggml_stubs.cu",
|
| 28 |
+
"vendor/src/ggml-cuda/convert.cu",
|
| 29 |
+
"vendor/src/ggml-cuda/quantize.cu",
|
| 30 |
+
# headers are listed so the builder stages them; only the files above are compiled
|
| 31 |
+
"vendor/include/ggml-alloc.h",
|
| 32 |
+
"vendor/include/ggml-backend.h",
|
| 33 |
+
"vendor/include/ggml-cuda.h",
|
| 34 |
+
"vendor/include/ggml.h",
|
| 35 |
+
"vendor/include/gguf.h",
|
| 36 |
+
"vendor/src/ggml-common.h",
|
| 37 |
+
"vendor/src/ggml-cuda/common.cuh",
|
| 38 |
+
"vendor/src/ggml-cuda/convert.cuh",
|
| 39 |
+
"vendor/src/ggml-cuda/dequantize.cuh",
|
| 40 |
+
"vendor/src/ggml-cuda/mma.cuh",
|
| 41 |
+
"vendor/src/ggml-cuda/mmq-config-ampere.cuh",
|
| 42 |
+
"vendor/src/ggml-cuda/mmq-config-blackwell.cuh",
|
| 43 |
+
"vendor/src/ggml-cuda/mmq-config-cdna.cuh",
|
| 44 |
+
"vendor/src/ggml-cuda/mmq-config-pascal.cuh",
|
| 45 |
+
"vendor/src/ggml-cuda/mmq-config-rdna2.cuh",
|
| 46 |
+
"vendor/src/ggml-cuda/mmq-config-rdna3-5.cuh",
|
| 47 |
+
"vendor/src/ggml-cuda/mmq-config-rdna3.cuh",
|
| 48 |
+
"vendor/src/ggml-cuda/mmq-config-rdna4.cuh",
|
| 49 |
+
"vendor/src/ggml-cuda/mmq-load-tiles.cuh",
|
| 50 |
+
"vendor/src/ggml-cuda/mmq-vec-dot.cuh",
|
| 51 |
+
"vendor/src/ggml-cuda/mmq.cuh",
|
| 52 |
+
"vendor/src/ggml-cuda/mmvf.cuh",
|
| 53 |
+
"vendor/src/ggml-cuda/mmvq.cuh",
|
| 54 |
+
"vendor/src/ggml-cuda/mmvq-impl.cuh",
|
| 55 |
+
"vendor/src/ggml-cuda/quantize.cuh",
|
| 56 |
+
"vendor/src/ggml-cuda/unary.cuh",
|
| 57 |
+
"vendor/src/ggml-cuda/vecdotq.cuh",
|
| 58 |
+
"vendor/src/ggml-cuda/vendors/cuda.h",
|
| 59 |
+
"vendor/src/ggml-impl.h",
|
| 60 |
+
]
|
| 61 |
+
# ggml's half/bfloat16 arithmetic needs the operators torch's build disables
|
| 62 |
+
cuda-flags = [
|
| 63 |
+
"-DGGML_USE_CUDA",
|
| 64 |
+
"-DNDEBUG",
|
| 65 |
+
"-U__CUDA_NO_HALF_OPERATORS__",
|
| 66 |
+
"-U__CUDA_NO_HALF_CONVERSIONS__",
|
| 67 |
+
"-U__CUDA_NO_HALF2_OPERATORS__",
|
| 68 |
+
"-U__CUDA_NO_BFLOAT16_CONVERSIONS__",
|
| 69 |
+
"-U__CUDA_NO_BFLOAT16_OPERATORS__",
|
| 70 |
+
"-U__CUDA_NO_BFLOAT162_OPERATORS__",
|
| 71 |
+
"--expt-relaxed-constexpr",
|
| 72 |
+
"--expt-extended-lambda",
|
| 73 |
+
]
|
| 74 |
+
cxx-flags = ["-DGGML_USE_CUDA", "-DNDEBUG"]
|
build/torch210-cxx11-cu126-x86_64-linux/__init__.py
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Compute directly on the packed blocks of a GGUF checkpoint.
|
| 2 |
+
|
| 3 |
+
A GGUF weight is stored as blocks of 32 or 256 values sharing a scale. These kernels read that
|
| 4 |
+
layout as it is, so a quantized model can be loaded and run without ever materializing a dense
|
| 5 |
+
copy — which is the whole memory saving.
|
| 6 |
+
|
| 7 |
+
Ported from llama.cpp's ggml-cuda; `vendor/UPSTREAM` pins the revision. The ops are named for what
|
| 8 |
+
they do rather than for a backend: each backend registers its own implementation of the same
|
| 9 |
+
schema, so calls dispatch on the tensor's device.
|
| 10 |
+
"""
|
| 11 |
+
|
| 12 |
+
import torch
|
| 13 |
+
|
| 14 |
+
from ._ops import add_op_namespace_prefix, ops
|
| 15 |
+
|
| 16 |
+
|
| 17 |
+
__all__ = ["GEMV_TYPES", "MAX_GEMV_ROWS", "dequantize", "mul_mat_vec"]
|
| 18 |
+
|
| 19 |
+
# Upstream's MMVQ_MAX_BATCH_SIZE: `mul_mat_vec` has no implementation beyond this many rows, so a
|
| 20 |
+
# caller with more (prefill) dequantizes and uses an ordinary matmul.
|
| 21 |
+
MAX_GEMV_ROWS = 8
|
| 22 |
+
|
| 23 |
+
# ggml type ids `mul_mat_vec` implements: Q4_0/Q4_1/Q5_0/Q5_1/Q8_0, the K quants, and the IQ quants.
|
| 24 |
+
# `dequantize` covers more, so check this one before choosing the fused path.
|
| 25 |
+
GEMV_TYPES = frozenset({2, 3, 6, 7, 8, 10, 11, 12, 13, 14, 16, 17, 18, 19, 20, 21, 22, 23, 29, 39, 40, 41, 42})
|
| 26 |
+
|
| 27 |
+
|
| 28 |
+
def dequantize(
|
| 29 |
+
blocks: torch.Tensor, ggml_type: int, rows: int, cols: int, dtype: torch.dtype
|
| 30 |
+
) -> torch.Tensor:
|
| 31 |
+
"""`(rows, bytes_per_row)` uint8 blocks -> `(rows, cols)` values of `dtype`."""
|
| 32 |
+
return ops.dequantize(blocks, ggml_type, rows, cols, dtype)
|
| 33 |
+
|
| 34 |
+
|
| 35 |
+
def mul_mat_vec(
|
| 36 |
+
blocks: torch.Tensor, x: torch.Tensor, ggml_type: int, out_features: int
|
| 37 |
+
) -> torch.Tensor:
|
| 38 |
+
"""Fused dequantize-gemv: `x @ blocks.T` without unpacking `blocks`.
|
| 39 |
+
|
| 40 |
+
`x` is `(rows, in_features)` and `rows` must be at most `MAX_GEMV_ROWS`. The result is f32
|
| 41 |
+
whatever `x`'s dtype was, since the kernel writes an f32 destination; cast it at the call site,
|
| 42 |
+
where the cast can be fused into whatever consumes it.
|
| 43 |
+
"""
|
| 44 |
+
return ops.mul_mat_vec(blocks, x, ggml_type, out_features)
|
| 45 |
+
|
| 46 |
+
|
| 47 |
+
# Without these, torch.compile cannot trace the ops and breaks the graph at every call.
|
| 48 |
+
@torch.library.register_fake(add_op_namespace_prefix("dequantize"))
|
| 49 |
+
def _dequantize_fake(blocks, ggml_type, rows, cols, dtype):
|
| 50 |
+
return blocks.new_empty((rows, cols), dtype=dtype)
|
| 51 |
+
|
| 52 |
+
|
| 53 |
+
@torch.library.register_fake(add_op_namespace_prefix("mul_mat_vec"))
|
| 54 |
+
def _mul_mat_vec_fake(blocks, x, ggml_type, out_features):
|
| 55 |
+
return x.new_empty((x.shape[0], out_features), dtype=torch.float32)
|
build/torch210-cxx11-cu126-x86_64-linux/_gguf_kernels_20260805124229.abi3.so
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:deef7081403683a708ba874d97321243281a1b6e9e1f23ae06c930f06459f3b1
|
| 3 |
+
size 26692640
|
build/torch210-cxx11-cu126-x86_64-linux/_ops.py
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import torch
|
| 2 |
+
from . import _gguf_kernels_20260805124229
|
| 3 |
+
ops = torch.ops._gguf_kernels_20260805124229
|
| 4 |
+
|
| 5 |
+
def add_op_namespace_prefix(op_name: str):
|
| 6 |
+
"""
|
| 7 |
+
Prefix op by namespace.
|
| 8 |
+
"""
|
| 9 |
+
return f"_gguf_kernels_20260805124229::{op_name}"
|
build/torch210-cxx11-cu126-x86_64-linux/gguf_kernels/__init__.py
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import ctypes
|
| 2 |
+
import sys
|
| 3 |
+
|
| 4 |
+
import importlib
|
| 5 |
+
from pathlib import Path
|
| 6 |
+
from types import ModuleType
|
| 7 |
+
|
| 8 |
+
def _import_from_path(file_path: Path) -> ModuleType:
|
| 9 |
+
# We cannot use the module name as-is, after adding it to `sys.modules`,
|
| 10 |
+
# it would also be used for other imports. So, we make a module name that
|
| 11 |
+
# depends on the path for it to be unique using the hex-encoded hash of
|
| 12 |
+
# the path.
|
| 13 |
+
path_hash = "{:x}".format(ctypes.c_size_t(hash(file_path.absolute())).value)
|
| 14 |
+
module_name = path_hash
|
| 15 |
+
spec = importlib.util.spec_from_file_location(module_name, file_path)
|
| 16 |
+
if spec is None:
|
| 17 |
+
raise ImportError(f"Cannot load spec for {module_name} from {file_path}")
|
| 18 |
+
module = importlib.util.module_from_spec(spec)
|
| 19 |
+
if module is None:
|
| 20 |
+
raise ImportError(f"Cannot load module {module_name} from spec")
|
| 21 |
+
sys.modules[module_name] = module
|
| 22 |
+
spec.loader.exec_module(module) # type: ignore
|
| 23 |
+
return module
|
| 24 |
+
|
| 25 |
+
|
| 26 |
+
globals().update(vars(_import_from_path(Path(__file__).parent.parent / "__init__.py")))
|
build/torch210-cxx11-cu126-x86_64-linux/metadata.json
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"version": 1,
|
| 3 |
+
"python-depends": []
|
| 4 |
+
}
|
build/torch210-cxx11-cu128-x86_64-linux/__init__.py
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Compute directly on the packed blocks of a GGUF checkpoint.
|
| 2 |
+
|
| 3 |
+
A GGUF weight is stored as blocks of 32 or 256 values sharing a scale. These kernels read that
|
| 4 |
+
layout as it is, so a quantized model can be loaded and run without ever materializing a dense
|
| 5 |
+
copy — which is the whole memory saving.
|
| 6 |
+
|
| 7 |
+
Ported from llama.cpp's ggml-cuda; `vendor/UPSTREAM` pins the revision. The ops are named for what
|
| 8 |
+
they do rather than for a backend: each backend registers its own implementation of the same
|
| 9 |
+
schema, so calls dispatch on the tensor's device.
|
| 10 |
+
"""
|
| 11 |
+
|
| 12 |
+
import torch
|
| 13 |
+
|
| 14 |
+
from ._ops import add_op_namespace_prefix, ops
|
| 15 |
+
|
| 16 |
+
|
| 17 |
+
__all__ = ["GEMV_TYPES", "MAX_GEMV_ROWS", "dequantize", "mul_mat_vec"]
|
| 18 |
+
|
| 19 |
+
# Upstream's MMVQ_MAX_BATCH_SIZE: `mul_mat_vec` has no implementation beyond this many rows, so a
|
| 20 |
+
# caller with more (prefill) dequantizes and uses an ordinary matmul.
|
| 21 |
+
MAX_GEMV_ROWS = 8
|
| 22 |
+
|
| 23 |
+
# ggml type ids `mul_mat_vec` implements: Q4_0/Q4_1/Q5_0/Q5_1/Q8_0, the K quants, and the IQ quants.
|
| 24 |
+
# `dequantize` covers more, so check this one before choosing the fused path.
|
| 25 |
+
GEMV_TYPES = frozenset({2, 3, 6, 7, 8, 10, 11, 12, 13, 14, 16, 17, 18, 19, 20, 21, 22, 23, 29, 39, 40, 41, 42})
|
| 26 |
+
|
| 27 |
+
|
| 28 |
+
def dequantize(
|
| 29 |
+
blocks: torch.Tensor, ggml_type: int, rows: int, cols: int, dtype: torch.dtype
|
| 30 |
+
) -> torch.Tensor:
|
| 31 |
+
"""`(rows, bytes_per_row)` uint8 blocks -> `(rows, cols)` values of `dtype`."""
|
| 32 |
+
return ops.dequantize(blocks, ggml_type, rows, cols, dtype)
|
| 33 |
+
|
| 34 |
+
|
| 35 |
+
def mul_mat_vec(
|
| 36 |
+
blocks: torch.Tensor, x: torch.Tensor, ggml_type: int, out_features: int
|
| 37 |
+
) -> torch.Tensor:
|
| 38 |
+
"""Fused dequantize-gemv: `x @ blocks.T` without unpacking `blocks`.
|
| 39 |
+
|
| 40 |
+
`x` is `(rows, in_features)` and `rows` must be at most `MAX_GEMV_ROWS`. The result is f32
|
| 41 |
+
whatever `x`'s dtype was, since the kernel writes an f32 destination; cast it at the call site,
|
| 42 |
+
where the cast can be fused into whatever consumes it.
|
| 43 |
+
"""
|
| 44 |
+
return ops.mul_mat_vec(blocks, x, ggml_type, out_features)
|
| 45 |
+
|
| 46 |
+
|
| 47 |
+
# Without these, torch.compile cannot trace the ops and breaks the graph at every call.
|
| 48 |
+
@torch.library.register_fake(add_op_namespace_prefix("dequantize"))
|
| 49 |
+
def _dequantize_fake(blocks, ggml_type, rows, cols, dtype):
|
| 50 |
+
return blocks.new_empty((rows, cols), dtype=dtype)
|
| 51 |
+
|
| 52 |
+
|
| 53 |
+
@torch.library.register_fake(add_op_namespace_prefix("mul_mat_vec"))
|
| 54 |
+
def _mul_mat_vec_fake(blocks, x, ggml_type, out_features):
|
| 55 |
+
return x.new_empty((x.shape[0], out_features), dtype=torch.float32)
|
build/torch210-cxx11-cu128-x86_64-linux/_gguf_kernels_20260805124229.abi3.so
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:b6cba7d21629a2a2269bd06de30ace18b373266c7e74e75e11f093cc27eec066
|
| 3 |
+
size 39064328
|
build/torch210-cxx11-cu128-x86_64-linux/_ops.py
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import torch
|
| 2 |
+
from . import _gguf_kernels_20260805124229
|
| 3 |
+
ops = torch.ops._gguf_kernels_20260805124229
|
| 4 |
+
|
| 5 |
+
def add_op_namespace_prefix(op_name: str):
|
| 6 |
+
"""
|
| 7 |
+
Prefix op by namespace.
|
| 8 |
+
"""
|
| 9 |
+
return f"_gguf_kernels_20260805124229::{op_name}"
|
build/torch210-cxx11-cu128-x86_64-linux/gguf_kernels/__init__.py
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import ctypes
|
| 2 |
+
import sys
|
| 3 |
+
|
| 4 |
+
import importlib
|
| 5 |
+
from pathlib import Path
|
| 6 |
+
from types import ModuleType
|
| 7 |
+
|
| 8 |
+
def _import_from_path(file_path: Path) -> ModuleType:
|
| 9 |
+
# We cannot use the module name as-is, after adding it to `sys.modules`,
|
| 10 |
+
# it would also be used for other imports. So, we make a module name that
|
| 11 |
+
# depends on the path for it to be unique using the hex-encoded hash of
|
| 12 |
+
# the path.
|
| 13 |
+
path_hash = "{:x}".format(ctypes.c_size_t(hash(file_path.absolute())).value)
|
| 14 |
+
module_name = path_hash
|
| 15 |
+
spec = importlib.util.spec_from_file_location(module_name, file_path)
|
| 16 |
+
if spec is None:
|
| 17 |
+
raise ImportError(f"Cannot load spec for {module_name} from {file_path}")
|
| 18 |
+
module = importlib.util.module_from_spec(spec)
|
| 19 |
+
if module is None:
|
| 20 |
+
raise ImportError(f"Cannot load module {module_name} from spec")
|
| 21 |
+
sys.modules[module_name] = module
|
| 22 |
+
spec.loader.exec_module(module) # type: ignore
|
| 23 |
+
return module
|
| 24 |
+
|
| 25 |
+
|
| 26 |
+
globals().update(vars(_import_from_path(Path(__file__).parent.parent / "__init__.py")))
|
build/torch210-cxx11-cu128-x86_64-linux/metadata.json
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"version": 1,
|
| 3 |
+
"python-depends": []
|
| 4 |
+
}
|
build/torch210-cxx11-cu130-x86_64-linux/__init__.py
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Compute directly on the packed blocks of a GGUF checkpoint.
|
| 2 |
+
|
| 3 |
+
A GGUF weight is stored as blocks of 32 or 256 values sharing a scale. These kernels read that
|
| 4 |
+
layout as it is, so a quantized model can be loaded and run without ever materializing a dense
|
| 5 |
+
copy — which is the whole memory saving.
|
| 6 |
+
|
| 7 |
+
Ported from llama.cpp's ggml-cuda; `vendor/UPSTREAM` pins the revision. The ops are named for what
|
| 8 |
+
they do rather than for a backend: each backend registers its own implementation of the same
|
| 9 |
+
schema, so calls dispatch on the tensor's device.
|
| 10 |
+
"""
|
| 11 |
+
|
| 12 |
+
import torch
|
| 13 |
+
|
| 14 |
+
from ._ops import add_op_namespace_prefix, ops
|
| 15 |
+
|
| 16 |
+
|
| 17 |
+
__all__ = ["GEMV_TYPES", "MAX_GEMV_ROWS", "dequantize", "mul_mat_vec"]
|
| 18 |
+
|
| 19 |
+
# Upstream's MMVQ_MAX_BATCH_SIZE: `mul_mat_vec` has no implementation beyond this many rows, so a
|
| 20 |
+
# caller with more (prefill) dequantizes and uses an ordinary matmul.
|
| 21 |
+
MAX_GEMV_ROWS = 8
|
| 22 |
+
|
| 23 |
+
# ggml type ids `mul_mat_vec` implements: Q4_0/Q4_1/Q5_0/Q5_1/Q8_0, the K quants, and the IQ quants.
|
| 24 |
+
# `dequantize` covers more, so check this one before choosing the fused path.
|
| 25 |
+
GEMV_TYPES = frozenset({2, 3, 6, 7, 8, 10, 11, 12, 13, 14, 16, 17, 18, 19, 20, 21, 22, 23, 29, 39, 40, 41, 42})
|
| 26 |
+
|
| 27 |
+
|
| 28 |
+
def dequantize(
|
| 29 |
+
blocks: torch.Tensor, ggml_type: int, rows: int, cols: int, dtype: torch.dtype
|
| 30 |
+
) -> torch.Tensor:
|
| 31 |
+
"""`(rows, bytes_per_row)` uint8 blocks -> `(rows, cols)` values of `dtype`."""
|
| 32 |
+
return ops.dequantize(blocks, ggml_type, rows, cols, dtype)
|
| 33 |
+
|
| 34 |
+
|
| 35 |
+
def mul_mat_vec(
|
| 36 |
+
blocks: torch.Tensor, x: torch.Tensor, ggml_type: int, out_features: int
|
| 37 |
+
) -> torch.Tensor:
|
| 38 |
+
"""Fused dequantize-gemv: `x @ blocks.T` without unpacking `blocks`.
|
| 39 |
+
|
| 40 |
+
`x` is `(rows, in_features)` and `rows` must be at most `MAX_GEMV_ROWS`. The result is f32
|
| 41 |
+
whatever `x`'s dtype was, since the kernel writes an f32 destination; cast it at the call site,
|
| 42 |
+
where the cast can be fused into whatever consumes it.
|
| 43 |
+
"""
|
| 44 |
+
return ops.mul_mat_vec(blocks, x, ggml_type, out_features)
|
| 45 |
+
|
| 46 |
+
|
| 47 |
+
# Without these, torch.compile cannot trace the ops and breaks the graph at every call.
|
| 48 |
+
@torch.library.register_fake(add_op_namespace_prefix("dequantize"))
|
| 49 |
+
def _dequantize_fake(blocks, ggml_type, rows, cols, dtype):
|
| 50 |
+
return blocks.new_empty((rows, cols), dtype=dtype)
|
| 51 |
+
|
| 52 |
+
|
| 53 |
+
@torch.library.register_fake(add_op_namespace_prefix("mul_mat_vec"))
|
| 54 |
+
def _mul_mat_vec_fake(blocks, x, ggml_type, out_features):
|
| 55 |
+
return x.new_empty((x.shape[0], out_features), dtype=torch.float32)
|
build/torch210-cxx11-cu130-x86_64-linux/_gguf_kernels_20260805124229.abi3.so
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:b4e935328add4b20b3761b3ab018967f2b61030491865b841c455e6a25702e4e
|
| 3 |
+
size 39318224
|
build/torch210-cxx11-cu130-x86_64-linux/_ops.py
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import torch
|
| 2 |
+
from . import _gguf_kernels_20260805124229
|
| 3 |
+
ops = torch.ops._gguf_kernels_20260805124229
|
| 4 |
+
|
| 5 |
+
def add_op_namespace_prefix(op_name: str):
|
| 6 |
+
"""
|
| 7 |
+
Prefix op by namespace.
|
| 8 |
+
"""
|
| 9 |
+
return f"_gguf_kernels_20260805124229::{op_name}"
|
build/torch210-cxx11-cu130-x86_64-linux/gguf_kernels/__init__.py
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import ctypes
|
| 2 |
+
import sys
|
| 3 |
+
|
| 4 |
+
import importlib
|
| 5 |
+
from pathlib import Path
|
| 6 |
+
from types import ModuleType
|
| 7 |
+
|
| 8 |
+
def _import_from_path(file_path: Path) -> ModuleType:
|
| 9 |
+
# We cannot use the module name as-is, after adding it to `sys.modules`,
|
| 10 |
+
# it would also be used for other imports. So, we make a module name that
|
| 11 |
+
# depends on the path for it to be unique using the hex-encoded hash of
|
| 12 |
+
# the path.
|
| 13 |
+
path_hash = "{:x}".format(ctypes.c_size_t(hash(file_path.absolute())).value)
|
| 14 |
+
module_name = path_hash
|
| 15 |
+
spec = importlib.util.spec_from_file_location(module_name, file_path)
|
| 16 |
+
if spec is None:
|
| 17 |
+
raise ImportError(f"Cannot load spec for {module_name} from {file_path}")
|
| 18 |
+
module = importlib.util.module_from_spec(spec)
|
| 19 |
+
if module is None:
|
| 20 |
+
raise ImportError(f"Cannot load module {module_name} from spec")
|
| 21 |
+
sys.modules[module_name] = module
|
| 22 |
+
spec.loader.exec_module(module) # type: ignore
|
| 23 |
+
return module
|
| 24 |
+
|
| 25 |
+
|
| 26 |
+
globals().update(vars(_import_from_path(Path(__file__).parent.parent / "__init__.py")))
|
build/torch210-cxx11-cu130-x86_64-linux/metadata.json
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"version": 1,
|
| 3 |
+
"python-depends": []
|
| 4 |
+
}
|
build/torch28-cxx11-cu126-x86_64-linux/__init__.py
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Compute directly on the packed blocks of a GGUF checkpoint.
|
| 2 |
+
|
| 3 |
+
A GGUF weight is stored as blocks of 32 or 256 values sharing a scale. These kernels read that
|
| 4 |
+
layout as it is, so a quantized model can be loaded and run without ever materializing a dense
|
| 5 |
+
copy — which is the whole memory saving.
|
| 6 |
+
|
| 7 |
+
Ported from llama.cpp's ggml-cuda; `vendor/UPSTREAM` pins the revision. The ops are named for what
|
| 8 |
+
they do rather than for a backend: each backend registers its own implementation of the same
|
| 9 |
+
schema, so calls dispatch on the tensor's device.
|
| 10 |
+
"""
|
| 11 |
+
|
| 12 |
+
import torch
|
| 13 |
+
|
| 14 |
+
from ._ops import add_op_namespace_prefix, ops
|
| 15 |
+
|
| 16 |
+
|
| 17 |
+
__all__ = ["GEMV_TYPES", "MAX_GEMV_ROWS", "dequantize", "mul_mat_vec"]
|
| 18 |
+
|
| 19 |
+
# Upstream's MMVQ_MAX_BATCH_SIZE: `mul_mat_vec` has no implementation beyond this many rows, so a
|
| 20 |
+
# caller with more (prefill) dequantizes and uses an ordinary matmul.
|
| 21 |
+
MAX_GEMV_ROWS = 8
|
| 22 |
+
|
| 23 |
+
# ggml type ids `mul_mat_vec` implements: Q4_0/Q4_1/Q5_0/Q5_1/Q8_0, the K quants, and the IQ quants.
|
| 24 |
+
# `dequantize` covers more, so check this one before choosing the fused path.
|
| 25 |
+
GEMV_TYPES = frozenset({2, 3, 6, 7, 8, 10, 11, 12, 13, 14, 16, 17, 18, 19, 20, 21, 22, 23, 29, 39, 40, 41, 42})
|
| 26 |
+
|
| 27 |
+
|
| 28 |
+
def dequantize(
|
| 29 |
+
blocks: torch.Tensor, ggml_type: int, rows: int, cols: int, dtype: torch.dtype
|
| 30 |
+
) -> torch.Tensor:
|
| 31 |
+
"""`(rows, bytes_per_row)` uint8 blocks -> `(rows, cols)` values of `dtype`."""
|
| 32 |
+
return ops.dequantize(blocks, ggml_type, rows, cols, dtype)
|
| 33 |
+
|
| 34 |
+
|
| 35 |
+
def mul_mat_vec(
|
| 36 |
+
blocks: torch.Tensor, x: torch.Tensor, ggml_type: int, out_features: int
|
| 37 |
+
) -> torch.Tensor:
|
| 38 |
+
"""Fused dequantize-gemv: `x @ blocks.T` without unpacking `blocks`.
|
| 39 |
+
|
| 40 |
+
`x` is `(rows, in_features)` and `rows` must be at most `MAX_GEMV_ROWS`. The result is f32
|
| 41 |
+
whatever `x`'s dtype was, since the kernel writes an f32 destination; cast it at the call site,
|
| 42 |
+
where the cast can be fused into whatever consumes it.
|
| 43 |
+
"""
|
| 44 |
+
return ops.mul_mat_vec(blocks, x, ggml_type, out_features)
|
| 45 |
+
|
| 46 |
+
|
| 47 |
+
# Without these, torch.compile cannot trace the ops and breaks the graph at every call.
|
| 48 |
+
@torch.library.register_fake(add_op_namespace_prefix("dequantize"))
|
| 49 |
+
def _dequantize_fake(blocks, ggml_type, rows, cols, dtype):
|
| 50 |
+
return blocks.new_empty((rows, cols), dtype=dtype)
|
| 51 |
+
|
| 52 |
+
|
| 53 |
+
@torch.library.register_fake(add_op_namespace_prefix("mul_mat_vec"))
|
| 54 |
+
def _mul_mat_vec_fake(blocks, x, ggml_type, out_features):
|
| 55 |
+
return x.new_empty((x.shape[0], out_features), dtype=torch.float32)
|
build/torch28-cxx11-cu126-x86_64-linux/_gguf_kernels_20260805124229.abi3.so
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:6708d42e7390b3a6fe316852e3857716defd991e5861031c8d04a1e7b4e0260f
|
| 3 |
+
size 26686512
|
build/torch28-cxx11-cu126-x86_64-linux/_ops.py
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import torch
|
| 2 |
+
from . import _gguf_kernels_20260805124229
|
| 3 |
+
ops = torch.ops._gguf_kernels_20260805124229
|
| 4 |
+
|
| 5 |
+
def add_op_namespace_prefix(op_name: str):
|
| 6 |
+
"""
|
| 7 |
+
Prefix op by namespace.
|
| 8 |
+
"""
|
| 9 |
+
return f"_gguf_kernels_20260805124229::{op_name}"
|
build/torch28-cxx11-cu126-x86_64-linux/gguf_kernels/__init__.py
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import ctypes
|
| 2 |
+
import sys
|
| 3 |
+
|
| 4 |
+
import importlib
|
| 5 |
+
from pathlib import Path
|
| 6 |
+
from types import ModuleType
|
| 7 |
+
|
| 8 |
+
def _import_from_path(file_path: Path) -> ModuleType:
|
| 9 |
+
# We cannot use the module name as-is, after adding it to `sys.modules`,
|
| 10 |
+
# it would also be used for other imports. So, we make a module name that
|
| 11 |
+
# depends on the path for it to be unique using the hex-encoded hash of
|
| 12 |
+
# the path.
|
| 13 |
+
path_hash = "{:x}".format(ctypes.c_size_t(hash(file_path.absolute())).value)
|
| 14 |
+
module_name = path_hash
|
| 15 |
+
spec = importlib.util.spec_from_file_location(module_name, file_path)
|
| 16 |
+
if spec is None:
|
| 17 |
+
raise ImportError(f"Cannot load spec for {module_name} from {file_path}")
|
| 18 |
+
module = importlib.util.module_from_spec(spec)
|
| 19 |
+
if module is None:
|
| 20 |
+
raise ImportError(f"Cannot load module {module_name} from spec")
|
| 21 |
+
sys.modules[module_name] = module
|
| 22 |
+
spec.loader.exec_module(module) # type: ignore
|
| 23 |
+
return module
|
| 24 |
+
|
| 25 |
+
|
| 26 |
+
globals().update(vars(_import_from_path(Path(__file__).parent.parent / "__init__.py")))
|
build/torch28-cxx11-cu126-x86_64-linux/metadata.json
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"version": 1,
|
| 3 |
+
"python-depends": []
|
| 4 |
+
}
|
build/torch28-cxx11-cu128-x86_64-linux/__init__.py
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Compute directly on the packed blocks of a GGUF checkpoint.
|
| 2 |
+
|
| 3 |
+
A GGUF weight is stored as blocks of 32 or 256 values sharing a scale. These kernels read that
|
| 4 |
+
layout as it is, so a quantized model can be loaded and run without ever materializing a dense
|
| 5 |
+
copy — which is the whole memory saving.
|
| 6 |
+
|
| 7 |
+
Ported from llama.cpp's ggml-cuda; `vendor/UPSTREAM` pins the revision. The ops are named for what
|
| 8 |
+
they do rather than for a backend: each backend registers its own implementation of the same
|
| 9 |
+
schema, so calls dispatch on the tensor's device.
|
| 10 |
+
"""
|
| 11 |
+
|
| 12 |
+
import torch
|
| 13 |
+
|
| 14 |
+
from ._ops import add_op_namespace_prefix, ops
|
| 15 |
+
|
| 16 |
+
|
| 17 |
+
__all__ = ["GEMV_TYPES", "MAX_GEMV_ROWS", "dequantize", "mul_mat_vec"]
|
| 18 |
+
|
| 19 |
+
# Upstream's MMVQ_MAX_BATCH_SIZE: `mul_mat_vec` has no implementation beyond this many rows, so a
|
| 20 |
+
# caller with more (prefill) dequantizes and uses an ordinary matmul.
|
| 21 |
+
MAX_GEMV_ROWS = 8
|
| 22 |
+
|
| 23 |
+
# ggml type ids `mul_mat_vec` implements: Q4_0/Q4_1/Q5_0/Q5_1/Q8_0, the K quants, and the IQ quants.
|
| 24 |
+
# `dequantize` covers more, so check this one before choosing the fused path.
|
| 25 |
+
GEMV_TYPES = frozenset({2, 3, 6, 7, 8, 10, 11, 12, 13, 14, 16, 17, 18, 19, 20, 21, 22, 23, 29, 39, 40, 41, 42})
|
| 26 |
+
|
| 27 |
+
|
| 28 |
+
def dequantize(
|
| 29 |
+
blocks: torch.Tensor, ggml_type: int, rows: int, cols: int, dtype: torch.dtype
|
| 30 |
+
) -> torch.Tensor:
|
| 31 |
+
"""`(rows, bytes_per_row)` uint8 blocks -> `(rows, cols)` values of `dtype`."""
|
| 32 |
+
return ops.dequantize(blocks, ggml_type, rows, cols, dtype)
|
| 33 |
+
|
| 34 |
+
|
| 35 |
+
def mul_mat_vec(
|
| 36 |
+
blocks: torch.Tensor, x: torch.Tensor, ggml_type: int, out_features: int
|
| 37 |
+
) -> torch.Tensor:
|
| 38 |
+
"""Fused dequantize-gemv: `x @ blocks.T` without unpacking `blocks`.
|
| 39 |
+
|
| 40 |
+
`x` is `(rows, in_features)` and `rows` must be at most `MAX_GEMV_ROWS`. The result is f32
|
| 41 |
+
whatever `x`'s dtype was, since the kernel writes an f32 destination; cast it at the call site,
|
| 42 |
+
where the cast can be fused into whatever consumes it.
|
| 43 |
+
"""
|
| 44 |
+
return ops.mul_mat_vec(blocks, x, ggml_type, out_features)
|
| 45 |
+
|
| 46 |
+
|
| 47 |
+
# Without these, torch.compile cannot trace the ops and breaks the graph at every call.
|
| 48 |
+
@torch.library.register_fake(add_op_namespace_prefix("dequantize"))
|
| 49 |
+
def _dequantize_fake(blocks, ggml_type, rows, cols, dtype):
|
| 50 |
+
return blocks.new_empty((rows, cols), dtype=dtype)
|
| 51 |
+
|
| 52 |
+
|
| 53 |
+
@torch.library.register_fake(add_op_namespace_prefix("mul_mat_vec"))
|
| 54 |
+
def _mul_mat_vec_fake(blocks, x, ggml_type, out_features):
|
| 55 |
+
return x.new_empty((x.shape[0], out_features), dtype=torch.float32)
|
build/torch28-cxx11-cu128-x86_64-linux/_gguf_kernels_20260805124229.abi3.so
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:964ea6025655311cfebe2fb58eca589ace6d208222d793134a48925309ccf910
|
| 3 |
+
size 39054016
|
build/torch28-cxx11-cu128-x86_64-linux/_ops.py
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import torch
|
| 2 |
+
from . import _gguf_kernels_20260805124229
|
| 3 |
+
ops = torch.ops._gguf_kernels_20260805124229
|
| 4 |
+
|
| 5 |
+
def add_op_namespace_prefix(op_name: str):
|
| 6 |
+
"""
|
| 7 |
+
Prefix op by namespace.
|
| 8 |
+
"""
|
| 9 |
+
return f"_gguf_kernels_20260805124229::{op_name}"
|
build/torch28-cxx11-cu128-x86_64-linux/gguf_kernels/__init__.py
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import ctypes
|
| 2 |
+
import sys
|
| 3 |
+
|
| 4 |
+
import importlib
|
| 5 |
+
from pathlib import Path
|
| 6 |
+
from types import ModuleType
|
| 7 |
+
|
| 8 |
+
def _import_from_path(file_path: Path) -> ModuleType:
|
| 9 |
+
# We cannot use the module name as-is, after adding it to `sys.modules`,
|
| 10 |
+
# it would also be used for other imports. So, we make a module name that
|
| 11 |
+
# depends on the path for it to be unique using the hex-encoded hash of
|
| 12 |
+
# the path.
|
| 13 |
+
path_hash = "{:x}".format(ctypes.c_size_t(hash(file_path.absolute())).value)
|
| 14 |
+
module_name = path_hash
|
| 15 |
+
spec = importlib.util.spec_from_file_location(module_name, file_path)
|
| 16 |
+
if spec is None:
|
| 17 |
+
raise ImportError(f"Cannot load spec for {module_name} from {file_path}")
|
| 18 |
+
module = importlib.util.module_from_spec(spec)
|
| 19 |
+
if module is None:
|
| 20 |
+
raise ImportError(f"Cannot load module {module_name} from spec")
|
| 21 |
+
sys.modules[module_name] = module
|
| 22 |
+
spec.loader.exec_module(module) # type: ignore
|
| 23 |
+
return module
|
| 24 |
+
|
| 25 |
+
|
| 26 |
+
globals().update(vars(_import_from_path(Path(__file__).parent.parent / "__init__.py")))
|
build/torch28-cxx11-cu128-x86_64-linux/metadata.json
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"version": 1,
|
| 3 |
+
"python-depends": []
|
| 4 |
+
}
|
build/torch28-cxx11-cu129-x86_64-linux/__init__.py
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Compute directly on the packed blocks of a GGUF checkpoint.
|
| 2 |
+
|
| 3 |
+
A GGUF weight is stored as blocks of 32 or 256 values sharing a scale. These kernels read that
|
| 4 |
+
layout as it is, so a quantized model can be loaded and run without ever materializing a dense
|
| 5 |
+
copy — which is the whole memory saving.
|
| 6 |
+
|
| 7 |
+
Ported from llama.cpp's ggml-cuda; `vendor/UPSTREAM` pins the revision. The ops are named for what
|
| 8 |
+
they do rather than for a backend: each backend registers its own implementation of the same
|
| 9 |
+
schema, so calls dispatch on the tensor's device.
|
| 10 |
+
"""
|
| 11 |
+
|
| 12 |
+
import torch
|
| 13 |
+
|
| 14 |
+
from ._ops import add_op_namespace_prefix, ops
|
| 15 |
+
|
| 16 |
+
|
| 17 |
+
__all__ = ["GEMV_TYPES", "MAX_GEMV_ROWS", "dequantize", "mul_mat_vec"]
|
| 18 |
+
|
| 19 |
+
# Upstream's MMVQ_MAX_BATCH_SIZE: `mul_mat_vec` has no implementation beyond this many rows, so a
|
| 20 |
+
# caller with more (prefill) dequantizes and uses an ordinary matmul.
|
| 21 |
+
MAX_GEMV_ROWS = 8
|
| 22 |
+
|
| 23 |
+
# ggml type ids `mul_mat_vec` implements: Q4_0/Q4_1/Q5_0/Q5_1/Q8_0, the K quants, and the IQ quants.
|
| 24 |
+
# `dequantize` covers more, so check this one before choosing the fused path.
|
| 25 |
+
GEMV_TYPES = frozenset({2, 3, 6, 7, 8, 10, 11, 12, 13, 14, 16, 17, 18, 19, 20, 21, 22, 23, 29, 39, 40, 41, 42})
|
| 26 |
+
|
| 27 |
+
|
| 28 |
+
def dequantize(
|
| 29 |
+
blocks: torch.Tensor, ggml_type: int, rows: int, cols: int, dtype: torch.dtype
|
| 30 |
+
) -> torch.Tensor:
|
| 31 |
+
"""`(rows, bytes_per_row)` uint8 blocks -> `(rows, cols)` values of `dtype`."""
|
| 32 |
+
return ops.dequantize(blocks, ggml_type, rows, cols, dtype)
|
| 33 |
+
|
| 34 |
+
|
| 35 |
+
def mul_mat_vec(
|
| 36 |
+
blocks: torch.Tensor, x: torch.Tensor, ggml_type: int, out_features: int
|
| 37 |
+
) -> torch.Tensor:
|
| 38 |
+
"""Fused dequantize-gemv: `x @ blocks.T` without unpacking `blocks`.
|
| 39 |
+
|
| 40 |
+
`x` is `(rows, in_features)` and `rows` must be at most `MAX_GEMV_ROWS`. The result is f32
|
| 41 |
+
whatever `x`'s dtype was, since the kernel writes an f32 destination; cast it at the call site,
|
| 42 |
+
where the cast can be fused into whatever consumes it.
|
| 43 |
+
"""
|
| 44 |
+
return ops.mul_mat_vec(blocks, x, ggml_type, out_features)
|
| 45 |
+
|
| 46 |
+
|
| 47 |
+
# Without these, torch.compile cannot trace the ops and breaks the graph at every call.
|
| 48 |
+
@torch.library.register_fake(add_op_namespace_prefix("dequantize"))
|
| 49 |
+
def _dequantize_fake(blocks, ggml_type, rows, cols, dtype):
|
| 50 |
+
return blocks.new_empty((rows, cols), dtype=dtype)
|
| 51 |
+
|
| 52 |
+
|
| 53 |
+
@torch.library.register_fake(add_op_namespace_prefix("mul_mat_vec"))
|
| 54 |
+
def _mul_mat_vec_fake(blocks, x, ggml_type, out_features):
|
| 55 |
+
return x.new_empty((x.shape[0], out_features), dtype=torch.float32)
|
build/torch28-cxx11-cu129-x86_64-linux/_gguf_kernels_20260805124229.abi3.so
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:51b5f28bd29d9373e0a9a5046e7314af5061350b340646ab98dfa391fd4f8670
|
| 3 |
+
size 38993592
|
build/torch28-cxx11-cu129-x86_64-linux/_ops.py
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import torch
|
| 2 |
+
from . import _gguf_kernels_20260805124229
|
| 3 |
+
ops = torch.ops._gguf_kernels_20260805124229
|
| 4 |
+
|
| 5 |
+
def add_op_namespace_prefix(op_name: str):
|
| 6 |
+
"""
|
| 7 |
+
Prefix op by namespace.
|
| 8 |
+
"""
|
| 9 |
+
return f"_gguf_kernels_20260805124229::{op_name}"
|
build/torch28-cxx11-cu129-x86_64-linux/gguf_kernels/__init__.py
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import ctypes
|
| 2 |
+
import sys
|
| 3 |
+
|
| 4 |
+
import importlib
|
| 5 |
+
from pathlib import Path
|
| 6 |
+
from types import ModuleType
|
| 7 |
+
|
| 8 |
+
def _import_from_path(file_path: Path) -> ModuleType:
|
| 9 |
+
# We cannot use the module name as-is, after adding it to `sys.modules`,
|
| 10 |
+
# it would also be used for other imports. So, we make a module name that
|
| 11 |
+
# depends on the path for it to be unique using the hex-encoded hash of
|
| 12 |
+
# the path.
|
| 13 |
+
path_hash = "{:x}".format(ctypes.c_size_t(hash(file_path.absolute())).value)
|
| 14 |
+
module_name = path_hash
|
| 15 |
+
spec = importlib.util.spec_from_file_location(module_name, file_path)
|
| 16 |
+
if spec is None:
|
| 17 |
+
raise ImportError(f"Cannot load spec for {module_name} from {file_path}")
|
| 18 |
+
module = importlib.util.module_from_spec(spec)
|
| 19 |
+
if module is None:
|
| 20 |
+
raise ImportError(f"Cannot load module {module_name} from spec")
|
| 21 |
+
sys.modules[module_name] = module
|
| 22 |
+
spec.loader.exec_module(module) # type: ignore
|
| 23 |
+
return module
|
| 24 |
+
|
| 25 |
+
|
| 26 |
+
globals().update(vars(_import_from_path(Path(__file__).parent.parent / "__init__.py")))
|
build/torch28-cxx11-cu129-x86_64-linux/metadata.json
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"version": 1,
|
| 3 |
+
"python-depends": []
|
| 4 |
+
}
|
build/torch29-cxx11-cu126-x86_64-linux/__init__.py
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Compute directly on the packed blocks of a GGUF checkpoint.
|
| 2 |
+
|
| 3 |
+
A GGUF weight is stored as blocks of 32 or 256 values sharing a scale. These kernels read that
|
| 4 |
+
layout as it is, so a quantized model can be loaded and run without ever materializing a dense
|
| 5 |
+
copy — which is the whole memory saving.
|
| 6 |
+
|
| 7 |
+
Ported from llama.cpp's ggml-cuda; `vendor/UPSTREAM` pins the revision. The ops are named for what
|
| 8 |
+
they do rather than for a backend: each backend registers its own implementation of the same
|
| 9 |
+
schema, so calls dispatch on the tensor's device.
|
| 10 |
+
"""
|
| 11 |
+
|
| 12 |
+
import torch
|
| 13 |
+
|
| 14 |
+
from ._ops import add_op_namespace_prefix, ops
|
| 15 |
+
|
| 16 |
+
|
| 17 |
+
__all__ = ["GEMV_TYPES", "MAX_GEMV_ROWS", "dequantize", "mul_mat_vec"]
|
| 18 |
+
|
| 19 |
+
# Upstream's MMVQ_MAX_BATCH_SIZE: `mul_mat_vec` has no implementation beyond this many rows, so a
|
| 20 |
+
# caller with more (prefill) dequantizes and uses an ordinary matmul.
|
| 21 |
+
MAX_GEMV_ROWS = 8
|
| 22 |
+
|
| 23 |
+
# ggml type ids `mul_mat_vec` implements: Q4_0/Q4_1/Q5_0/Q5_1/Q8_0, the K quants, and the IQ quants.
|
| 24 |
+
# `dequantize` covers more, so check this one before choosing the fused path.
|
| 25 |
+
GEMV_TYPES = frozenset({2, 3, 6, 7, 8, 10, 11, 12, 13, 14, 16, 17, 18, 19, 20, 21, 22, 23, 29, 39, 40, 41, 42})
|
| 26 |
+
|
| 27 |
+
|
| 28 |
+
def dequantize(
|
| 29 |
+
blocks: torch.Tensor, ggml_type: int, rows: int, cols: int, dtype: torch.dtype
|
| 30 |
+
) -> torch.Tensor:
|
| 31 |
+
"""`(rows, bytes_per_row)` uint8 blocks -> `(rows, cols)` values of `dtype`."""
|
| 32 |
+
return ops.dequantize(blocks, ggml_type, rows, cols, dtype)
|
| 33 |
+
|
| 34 |
+
|
| 35 |
+
def mul_mat_vec(
|
| 36 |
+
blocks: torch.Tensor, x: torch.Tensor, ggml_type: int, out_features: int
|
| 37 |
+
) -> torch.Tensor:
|
| 38 |
+
"""Fused dequantize-gemv: `x @ blocks.T` without unpacking `blocks`.
|
| 39 |
+
|
| 40 |
+
`x` is `(rows, in_features)` and `rows` must be at most `MAX_GEMV_ROWS`. The result is f32
|
| 41 |
+
whatever `x`'s dtype was, since the kernel writes an f32 destination; cast it at the call site,
|
| 42 |
+
where the cast can be fused into whatever consumes it.
|
| 43 |
+
"""
|
| 44 |
+
return ops.mul_mat_vec(blocks, x, ggml_type, out_features)
|
| 45 |
+
|
| 46 |
+
|
| 47 |
+
# Without these, torch.compile cannot trace the ops and breaks the graph at every call.
|
| 48 |
+
@torch.library.register_fake(add_op_namespace_prefix("dequantize"))
|
| 49 |
+
def _dequantize_fake(blocks, ggml_type, rows, cols, dtype):
|
| 50 |
+
return blocks.new_empty((rows, cols), dtype=dtype)
|
| 51 |
+
|
| 52 |
+
|
| 53 |
+
@torch.library.register_fake(add_op_namespace_prefix("mul_mat_vec"))
|
| 54 |
+
def _mul_mat_vec_fake(blocks, x, ggml_type, out_features):
|
| 55 |
+
return x.new_empty((x.shape[0], out_features), dtype=torch.float32)
|
build/torch29-cxx11-cu126-x86_64-linux/_gguf_kernels_20260805124229.abi3.so
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:d7435e6aeaab83f149782dd9d4dd926012315c0e9162b2a141dcbc961da18ea9
|
| 3 |
+
size 26690648
|
build/torch29-cxx11-cu126-x86_64-linux/_ops.py
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import torch
|
| 2 |
+
from . import _gguf_kernels_20260805124229
|
| 3 |
+
ops = torch.ops._gguf_kernels_20260805124229
|
| 4 |
+
|
| 5 |
+
def add_op_namespace_prefix(op_name: str):
|
| 6 |
+
"""
|
| 7 |
+
Prefix op by namespace.
|
| 8 |
+
"""
|
| 9 |
+
return f"_gguf_kernels_20260805124229::{op_name}"
|
build/torch29-cxx11-cu126-x86_64-linux/gguf_kernels/__init__.py
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import ctypes
|
| 2 |
+
import sys
|
| 3 |
+
|
| 4 |
+
import importlib
|
| 5 |
+
from pathlib import Path
|
| 6 |
+
from types import ModuleType
|
| 7 |
+
|
| 8 |
+
def _import_from_path(file_path: Path) -> ModuleType:
|
| 9 |
+
# We cannot use the module name as-is, after adding it to `sys.modules`,
|
| 10 |
+
# it would also be used for other imports. So, we make a module name that
|
| 11 |
+
# depends on the path for it to be unique using the hex-encoded hash of
|
| 12 |
+
# the path.
|
| 13 |
+
path_hash = "{:x}".format(ctypes.c_size_t(hash(file_path.absolute())).value)
|
| 14 |
+
module_name = path_hash
|
| 15 |
+
spec = importlib.util.spec_from_file_location(module_name, file_path)
|
| 16 |
+
if spec is None:
|
| 17 |
+
raise ImportError(f"Cannot load spec for {module_name} from {file_path}")
|
| 18 |
+
module = importlib.util.module_from_spec(spec)
|
| 19 |
+
if module is None:
|
| 20 |
+
raise ImportError(f"Cannot load module {module_name} from spec")
|
| 21 |
+
sys.modules[module_name] = module
|
| 22 |
+
spec.loader.exec_module(module) # type: ignore
|
| 23 |
+
return module
|
| 24 |
+
|
| 25 |
+
|
| 26 |
+
globals().update(vars(_import_from_path(Path(__file__).parent.parent / "__init__.py")))
|
build/torch29-cxx11-cu126-x86_64-linux/metadata.json
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"version": 1,
|
| 3 |
+
"python-depends": []
|
| 4 |
+
}
|
build/torch29-cxx11-cu128-x86_64-linux/__init__.py
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Compute directly on the packed blocks of a GGUF checkpoint.
|
| 2 |
+
|
| 3 |
+
A GGUF weight is stored as blocks of 32 or 256 values sharing a scale. These kernels read that
|
| 4 |
+
layout as it is, so a quantized model can be loaded and run without ever materializing a dense
|
| 5 |
+
copy — which is the whole memory saving.
|
| 6 |
+
|
| 7 |
+
Ported from llama.cpp's ggml-cuda; `vendor/UPSTREAM` pins the revision. The ops are named for what
|
| 8 |
+
they do rather than for a backend: each backend registers its own implementation of the same
|
| 9 |
+
schema, so calls dispatch on the tensor's device.
|
| 10 |
+
"""
|
| 11 |
+
|
| 12 |
+
import torch
|
| 13 |
+
|
| 14 |
+
from ._ops import add_op_namespace_prefix, ops
|
| 15 |
+
|
| 16 |
+
|
| 17 |
+
__all__ = ["GEMV_TYPES", "MAX_GEMV_ROWS", "dequantize", "mul_mat_vec"]
|
| 18 |
+
|
| 19 |
+
# Upstream's MMVQ_MAX_BATCH_SIZE: `mul_mat_vec` has no implementation beyond this many rows, so a
|
| 20 |
+
# caller with more (prefill) dequantizes and uses an ordinary matmul.
|
| 21 |
+
MAX_GEMV_ROWS = 8
|
| 22 |
+
|
| 23 |
+
# ggml type ids `mul_mat_vec` implements: Q4_0/Q4_1/Q5_0/Q5_1/Q8_0, the K quants, and the IQ quants.
|
| 24 |
+
# `dequantize` covers more, so check this one before choosing the fused path.
|
| 25 |
+
GEMV_TYPES = frozenset({2, 3, 6, 7, 8, 10, 11, 12, 13, 14, 16, 17, 18, 19, 20, 21, 22, 23, 29, 39, 40, 41, 42})
|
| 26 |
+
|
| 27 |
+
|
| 28 |
+
def dequantize(
|
| 29 |
+
blocks: torch.Tensor, ggml_type: int, rows: int, cols: int, dtype: torch.dtype
|
| 30 |
+
) -> torch.Tensor:
|
| 31 |
+
"""`(rows, bytes_per_row)` uint8 blocks -> `(rows, cols)` values of `dtype`."""
|
| 32 |
+
return ops.dequantize(blocks, ggml_type, rows, cols, dtype)
|
| 33 |
+
|
| 34 |
+
|
| 35 |
+
def mul_mat_vec(
|
| 36 |
+
blocks: torch.Tensor, x: torch.Tensor, ggml_type: int, out_features: int
|
| 37 |
+
) -> torch.Tensor:
|
| 38 |
+
"""Fused dequantize-gemv: `x @ blocks.T` without unpacking `blocks`.
|
| 39 |
+
|
| 40 |
+
`x` is `(rows, in_features)` and `rows` must be at most `MAX_GEMV_ROWS`. The result is f32
|
| 41 |
+
whatever `x`'s dtype was, since the kernel writes an f32 destination; cast it at the call site,
|
| 42 |
+
where the cast can be fused into whatever consumes it.
|
| 43 |
+
"""
|
| 44 |
+
return ops.mul_mat_vec(blocks, x, ggml_type, out_features)
|
| 45 |
+
|
| 46 |
+
|
| 47 |
+
# Without these, torch.compile cannot trace the ops and breaks the graph at every call.
|
| 48 |
+
@torch.library.register_fake(add_op_namespace_prefix("dequantize"))
|
| 49 |
+
def _dequantize_fake(blocks, ggml_type, rows, cols, dtype):
|
| 50 |
+
return blocks.new_empty((rows, cols), dtype=dtype)
|
| 51 |
+
|
| 52 |
+
|
| 53 |
+
@torch.library.register_fake(add_op_namespace_prefix("mul_mat_vec"))
|
| 54 |
+
def _mul_mat_vec_fake(blocks, x, ggml_type, out_features):
|
| 55 |
+
return x.new_empty((x.shape[0], out_features), dtype=torch.float32)
|
build/torch29-cxx11-cu128-x86_64-linux/_gguf_kernels_20260805124229.abi3.so
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:1c141779c8750668e8681e6b803bdac2b6105ee861ff3331b59c0375493392a8
|
| 3 |
+
size 39058144
|
build/torch29-cxx11-cu128-x86_64-linux/_ops.py
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import torch
|
| 2 |
+
from . import _gguf_kernels_20260805124229
|
| 3 |
+
ops = torch.ops._gguf_kernels_20260805124229
|
| 4 |
+
|
| 5 |
+
def add_op_namespace_prefix(op_name: str):
|
| 6 |
+
"""
|
| 7 |
+
Prefix op by namespace.
|
| 8 |
+
"""
|
| 9 |
+
return f"_gguf_kernels_20260805124229::{op_name}"
|
build/torch29-cxx11-cu128-x86_64-linux/gguf_kernels/__init__.py
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import ctypes
|
| 2 |
+
import sys
|
| 3 |
+
|
| 4 |
+
import importlib
|
| 5 |
+
from pathlib import Path
|
| 6 |
+
from types import ModuleType
|
| 7 |
+
|
| 8 |
+
def _import_from_path(file_path: Path) -> ModuleType:
|
| 9 |
+
# We cannot use the module name as-is, after adding it to `sys.modules`,
|
| 10 |
+
# it would also be used for other imports. So, we make a module name that
|
| 11 |
+
# depends on the path for it to be unique using the hex-encoded hash of
|
| 12 |
+
# the path.
|
| 13 |
+
path_hash = "{:x}".format(ctypes.c_size_t(hash(file_path.absolute())).value)
|
| 14 |
+
module_name = path_hash
|
| 15 |
+
spec = importlib.util.spec_from_file_location(module_name, file_path)
|
| 16 |
+
if spec is None:
|
| 17 |
+
raise ImportError(f"Cannot load spec for {module_name} from {file_path}")
|
| 18 |
+
module = importlib.util.module_from_spec(spec)
|
| 19 |
+
if module is None:
|
| 20 |
+
raise ImportError(f"Cannot load module {module_name} from spec")
|
| 21 |
+
sys.modules[module_name] = module
|
| 22 |
+
spec.loader.exec_module(module) # type: ignore
|
| 23 |
+
return module
|
| 24 |
+
|
| 25 |
+
|
| 26 |
+
globals().update(vars(_import_from_path(Path(__file__).parent.parent / "__init__.py")))
|
build/torch29-cxx11-cu128-x86_64-linux/metadata.json
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"version": 1,
|
| 3 |
+
"python-depends": []
|
| 4 |
+
}
|
build/torch29-cxx11-cu130-x86_64-linux/__init__.py
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Compute directly on the packed blocks of a GGUF checkpoint.
|
| 2 |
+
|
| 3 |
+
A GGUF weight is stored as blocks of 32 or 256 values sharing a scale. These kernels read that
|
| 4 |
+
layout as it is, so a quantized model can be loaded and run without ever materializing a dense
|
| 5 |
+
copy — which is the whole memory saving.
|
| 6 |
+
|
| 7 |
+
Ported from llama.cpp's ggml-cuda; `vendor/UPSTREAM` pins the revision. The ops are named for what
|
| 8 |
+
they do rather than for a backend: each backend registers its own implementation of the same
|
| 9 |
+
schema, so calls dispatch on the tensor's device.
|
| 10 |
+
"""
|
| 11 |
+
|
| 12 |
+
import torch
|
| 13 |
+
|
| 14 |
+
from ._ops import add_op_namespace_prefix, ops
|
| 15 |
+
|
| 16 |
+
|
| 17 |
+
__all__ = ["GEMV_TYPES", "MAX_GEMV_ROWS", "dequantize", "mul_mat_vec"]
|
| 18 |
+
|
| 19 |
+
# Upstream's MMVQ_MAX_BATCH_SIZE: `mul_mat_vec` has no implementation beyond this many rows, so a
|
| 20 |
+
# caller with more (prefill) dequantizes and uses an ordinary matmul.
|
| 21 |
+
MAX_GEMV_ROWS = 8
|
| 22 |
+
|
| 23 |
+
# ggml type ids `mul_mat_vec` implements: Q4_0/Q4_1/Q5_0/Q5_1/Q8_0, the K quants, and the IQ quants.
|
| 24 |
+
# `dequantize` covers more, so check this one before choosing the fused path.
|
| 25 |
+
GEMV_TYPES = frozenset({2, 3, 6, 7, 8, 10, 11, 12, 13, 14, 16, 17, 18, 19, 20, 21, 22, 23, 29, 39, 40, 41, 42})
|
| 26 |
+
|
| 27 |
+
|
| 28 |
+
def dequantize(
|
| 29 |
+
blocks: torch.Tensor, ggml_type: int, rows: int, cols: int, dtype: torch.dtype
|
| 30 |
+
) -> torch.Tensor:
|
| 31 |
+
"""`(rows, bytes_per_row)` uint8 blocks -> `(rows, cols)` values of `dtype`."""
|
| 32 |
+
return ops.dequantize(blocks, ggml_type, rows, cols, dtype)
|
| 33 |
+
|
| 34 |
+
|
| 35 |
+
def mul_mat_vec(
|
| 36 |
+
blocks: torch.Tensor, x: torch.Tensor, ggml_type: int, out_features: int
|
| 37 |
+
) -> torch.Tensor:
|
| 38 |
+
"""Fused dequantize-gemv: `x @ blocks.T` without unpacking `blocks`.
|
| 39 |
+
|
| 40 |
+
`x` is `(rows, in_features)` and `rows` must be at most `MAX_GEMV_ROWS`. The result is f32
|
| 41 |
+
whatever `x`'s dtype was, since the kernel writes an f32 destination; cast it at the call site,
|
| 42 |
+
where the cast can be fused into whatever consumes it.
|
| 43 |
+
"""
|
| 44 |
+
return ops.mul_mat_vec(blocks, x, ggml_type, out_features)
|
| 45 |
+
|
| 46 |
+
|
| 47 |
+
# Without these, torch.compile cannot trace the ops and breaks the graph at every call.
|
| 48 |
+
@torch.library.register_fake(add_op_namespace_prefix("dequantize"))
|
| 49 |
+
def _dequantize_fake(blocks, ggml_type, rows, cols, dtype):
|
| 50 |
+
return blocks.new_empty((rows, cols), dtype=dtype)
|
| 51 |
+
|
| 52 |
+
|
| 53 |
+
@torch.library.register_fake(add_op_namespace_prefix("mul_mat_vec"))
|
| 54 |
+
def _mul_mat_vec_fake(blocks, x, ggml_type, out_features):
|
| 55 |
+
return x.new_empty((x.shape[0], out_features), dtype=torch.float32)
|
build/torch29-cxx11-cu130-x86_64-linux/_gguf_kernels_20260805124229.abi3.so
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:41f95273f40f722f1e7e64d5a9784f769ff48cbce511f383e88bd89b70495a8b
|
| 3 |
+
size 39312040
|