Skip to content
jeel00devPublic

Latest commit

 

History

314 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

vkML — Vulkan based machine learning library

A deep learning framework that runs on Vulkan compute.

License C++20 Python Vulkan Status


About vkML

vkML is a deep learning library. It gives you tensors, automatic differentiation, neural network layers, optimisers and a data loader — roughly the same API you already know from PyTorch — and it runs them on your GPU using Vulkan compute shaders instead of CUDA or ROCm.

The core is written in C++20 (about 16k lines, including the shaders), and the Python API is built with nanobind.

Tensors are lazy. When you write a + b, nothing runs yet — vkML just records the operation in a graph. The work is sent to the GPU when you actually need a result, so a whole expression can go over in a single submission.

import numpy as np
import vkml as V

device, why = V.best_device()   # the GPU if one is usable, otherwise the CPU
print(why)

model = V.nn.Sequential(
    V.nn.Flatten(),
    V.nn.Linear(784, 128), V.nn.ReLU(),
    V.nn.Linear(128, 10),
).to(device)

optimiser = V.optim.SGD(model.parameters(), lr=0.1, momentum=0.9)

for images, labels in loader:                     # vkml.data.DataLoader
    x = V.tensor(images, device=device)
    y = V.tensor(labels, device=device)

    optimiser.zero_grad()
    loss = V.nn.cross_entropy(model(x), y)
    loss.backward()
    optimiser.step()

Why Vulkan?

Most GPU deep learning runs on NVIDIA cards because it runs on CUDA. AMD has ROCm, but it only supports some cards — and mine is not one of them. That is the problem that started this project.

Vulkan is a different approach. It is a vendor-neutral API, and drivers exist for AMD, NVIDIA, Intel, Qualcomm, ARM and Apple (through MoltenVK). A compute shader compiled to SPIR-V can run on all of them.

The trade-off is real, and worth knowing before you start: there is no cuBLAS and no cuDNN here, so every kernel in vkML is one that had to be written by hand. In return, one build can potentially run anywhere.

A few Vulkan features make that trade cheaper than it sounds:

Feature What it gives us
bufferDeviceAddress Buffers become 64-bit pointers passed in push constants, so there are no descriptor sets or pools to manage per dispatch
Specialisation constants One SPIR-V module per operator family, specialised for the op, dtype and layout when the pipeline is created
scalarBlockLayout Push-constant structs have the same layout in GLSL and C++, so shape metadata is mirrored instead of translated
Timeline semaphores Submission and readback stay in sync without a fence for every dispatch

Installation

Step 1 — install the dependencies

vkML is compiled when you install it, so you need a few tools on your machine first. Pick your platform below.

Linux (Debian / Ubuntu)
sudo apt-get update
sudo apt-get install -y build-essential cmake ninja-build \
                        libvulkan-dev glslang-tools

That gives you a C++ compiler, CMake, the Vulkan development files and glslangValidator to compile the shaders.

If you do not have a GPU (or your driver is not working), you can install a software Vulkan driver and still use the library:

sudo apt-get install -y mesa-vulkan-drivers vulkan-tools
Linux (Fedora / RHEL)
sudo dnf install -y gcc-c++ cmake ninja-build \
                    vulkan-headers vulkan-loader-devel vulkan-loader

You also need a GLSL compiler, which provides either glslc or glslangValidator. We have not verified which package supplies it on Fedora, so we would rather not send you after the wrong name — if the build stops with "no GLSL compiler found", search your package manager for glslang or shaderc. Please open an issue with what worked and we will put it here.

Linux (Arch)
sudo pacman -S base-devel cmake ninja vulkan-headers vulkan-icd-loader glslang

glslang provides glslangValidator. If you would rather have glslc, install shaderc instead. Either one works.

macOS

macOS is not currently validated. It used to build on every commit; that job now runs only on request (.github/workflows/macos-moltenvk.yml), so nothing here is checked automatically and it may have drifted. The instructions are kept because they worked when they were written, not because they are being verified. Treat macOS as unsupported until that job is back in the pipeline.

Vulkan is not native on macOS, so you also need MoltenVK, which translates Vulkan to Metal. Homebrew has everything:

brew install cmake ninja molten-vk vulkan-loader vulkan-headers vulkan-tools glslang

The Vulkan loader has to be told where MoltenVK is, because Homebrew does not install it where the loader looks by default. Rather than guess the path, ask Homebrew for it:

export VK_ICD_FILENAMES="$(brew list molten-vk | grep -m1 'MoltenVK_icd.json')"

Add that line to your ~/.zshrc so it survives a new terminal.

Do not be tempted to write the path out by hand. Our own CI got it wrong three times: the file lives under etc/ on some versions and share/ on others, and brew --prefix does not point where you would expect. Asking brew list costs nothing and is always right.

Check it worked — this should list a device:

vulkaninfo --summary
Windows

You need three things:

  1. Visual Studio 2022 with the "Desktop development with C++" workload (download). The free Community edition is fine.
  2. CMake 3.25 or newer (download). Tick Also needed: a C++20 compiler with <format> — GCC 13+, MSVC 19.29+, or Clang 17+ with libc++. CMake fails at configure time with a message naming the requirement if the toolchain is older. "Add CMake to the system PATH" during setup.
  3. The Vulkan SDK from LunarG (download). This includes the headers, the loader and glslc, so it covers everything else vkML needs.

The Vulkan SDK installer normally sets the VULKAN_SDK environment variable, which is how CMake finds it. Open a new terminal after installing, or the variable will not be set in your current one. It is not guaranteed to be set at all — see Troubleshooting if CMake cannot find Vulkan afterwards.

Then run the install from a Developer Command Prompt for VS 2022 — that is the shell that has the MSVC compiler on its PATH.

Worth knowing: Windows is built and tested on every commit, but only as a CPU-only build, because the CI runners have no GPU.

The Windows build with Vulkan enabled has now been run on an AMD GPU, and it found real bugs — which is exactly what that kind of report is for. All of them are fixed: the build and packaging problems, an f32 → f16 rounding difference that made results driver-dependent, and the three kernels that declared more push constants than Vulkan's guaranteed 128-byte minimum. That last one meant those pipelines could not be created on a device reporting exactly 128, so much of the suite failed and MNIST could not train there.

The full suite now passes on that hardware, and both examples train. How each kernel was brought inside the guarantee is in docs/adr/0009.

Reports from other Windows GPUs are still very welcome — see If you have hardware we do not.

Step 2 — install vkML

You need Python 3.10 or newer. Clone the repository and install it:

git clone https://github.com/jeel00dev/vkml.git
cd vkml
pip install .

That one command builds the C++ core, compiles the shaders into the extension and installs the Python package. It takes a few minutes the first time.

vkML is not on PyPI yet, so installing from source is the only way for now.

Step 3 — check that it worked

python -c "import vkml; print(vkml.__version__); print(vkml.vulkan_device_names())"

You should see a version number and a list of your GPUs. If the list is empty, vkML installed correctly but cannot see a Vulkan device — see Troubleshooting below.

Installing without Vulkan

vkML also has a CPU backend, mostly used to check the GPU results against. If you want to build only that — for example on a machine with no Vulkan SDK — ask for it explicitly:

pip install . -C cmake.define.VKML_VULKAN=OFF

By default the build fails when the Vulkan SDK is missing rather than quietly giving you a CPU-only library, because that would not be the thing you asked to install.

One runtime dependency pip cannot install for you

vkML links against the Vulkan loader — libvulkan.so.1 on Linux, libvulkan.1.dylib on macOS, vulkan-1.dll on Windows. This is the small system library that finds your graphics driver. Without it, import vkml fails before you reach any Python code, and pip cannot fix that for you.

Most machines with working graphics already have it. On a headless server you may need to install it:

System Package
Debian / Ubuntu libvulkan1
Fedora / RHEL vulkan-loader
Arch vulkan-icd-loader
macOS brew install vulkan-loader
Windows included with the Vulkan SDK and with most GPU drivers

The loader is not the same thing as the driver. If you have the loader but no driver, vkML imports fine and vulkan_device_count() returns 0 — you can still use the CPU backend, but you have to ask for it.


Choosing a device

Using the GPU is an explicit choice. vkML never transparently falls back to the CPU, and this is deliberate rather than unfinished — a hidden fallback makes performance impossible to reason about, because the same code silently runs at very different speeds depending on the machine.

There are two ways to pick a device, and they behave differently on purpose.

Ask vkML to choose

device, why = vkml.best_device()
print(why)
# using Vulkan device 0: AMD Radeon RX 5600M (RADV NAVI10) (discrete, Vulkan
# 1.4.354, driver radv)

best_device() never raises. If no GPU is usable it returns the CPU and tells you why:

running on the CPU: the Vulkan loader could not create an instance
(VK_ERROR_INCOMPATIBLE_DRIVER); either no driver is installed, or none of the
installed drivers supports Vulkan 1.3. Call vkml.vulkan_device_reports() to see
every device the loader can find and what each one is missing. README.md's
Troubleshooting section covers installing a driver and the Vulkan loader.

It returns the reason rather than printing it, so you can log it, show it in a UI, or ignore it. It prefers a discrete GPU over an integrated one when both work, and names the one it picked.

This is the only path that falls back.

Name a device yourself

vkml.init_vulkan(0)
device = vkml.device("vulkan:0")

Naming a device is a request, and it is never quietly downgraded. If that GPU is not usable, init_vulkan raises with the reason — because someone who typed vulkan:1 wants that GPU, and handing back the CPU would hide the very thing they were asking about behind a number that merely looks slow.

If an operator has no GPU kernel

vkML raises rather than moving that one operator to the CPU behind your back:

NotImplementedError: backend 'vulkan:0' cannot evaluate op 'prod'. vkML does not
fall back to another device automatically -- doing so would move data through
host memory on every use and be far slower without saying so. Move this part of
the computation across explicitly, with `vkml.tensor(t.numpy(),
device=vkml.cpu)`, or open an issue if you need 'prod' on this backend.

Splitting a graph across devices means copying intermediates through host memory at every split, which we measured at roughly three times the cost of the arithmetic being carried. Doing that silently would turn a working model into a mysteriously slow one. One operator is affected today: prod. (max_pool2d on a non-contiguous input was the other until its shader learned to address planes through the same index mapping the CPU uses.)

The reasoning is written up in docs/adr/0008-backend-selection-and-cpu-fallback.md.


Building from source

If you want to work on vkML rather than just use it, build it with CMake directly. This gives you the C++ tests and the benchmarks too.

Linux and macOS

cmake --preset release -DVKML_VULKAN=ON
cmake --build build/release -j$(nproc)          # macOS: -j$(sysctl -n hw.ncpu)

The Python extension is written straight into python/vkml/, so you can use it by putting that folder on your path:

PYTHONPATH=python python -c "import vkml; print(vkml.__version__)"

Windows

Windows uses a multi-config generator, which ignores CMAKE_BUILD_TYPE. Do not use the presets there — pass the config to the build instead:

cmake -B build/msvc -DVKML_VULKAN=ON -DVKML_BUILD_PYTHON=ON
cmake --build build/msvc --config Release --parallel

Build options

Option Default What it does
VKML_VULKAN OFF Build the Vulkan backend. pip install turns this on for you; with CMake you pass it yourself, as above
VKML_BUILD_TESTS ON Build the C++ test suite
VKML_BUILD_PYTHON ON Build the Python extension
VKML_BUILD_BENCH ON Build the benchmarks
VKML_WERROR OFF Treat warnings as errors
VKML_SANITIZE OFF Enable ASan and UBSan

Presets: release, debug (warnings as errors), asan, relwithdebinfo.

Runtime switches

Separately from the build options above, a handful of VKML_* environment variables select debug output and tuning experiments at run time — VKML_VULKAN_DEBUG=1 traces every dispatch, VKML_EAGER=1 realizes each operation as it is built, VKML_COVERAGE=<path> records an operator-coverage table.

VKML_MIN_SPEC=1 is worth knowing about even if you never tune anything. It makes your device report the Vulkan 1.3 guaranteed minimums — 128 workgroup invocations, 16 KiB of shared memory, 128 bytes of push constants — instead of what it actually offers, and runs the whole stack against them. Every portability defect this project has had was a limit written against one machine, and this is the cheapest way to find the next one without owning the hardware. It only ever reports less than your GPU has, so anything that works under it genuinely works.

They are read once, at first use, and cached for the life of the process. They are configuration, not a control interface: changing one after vkML has started has no defined effect, because pipelines are already selected and cached from the earlier value. Set them before launching, not during.

Running the tests

The Python test suite compares every operator against PyTorch, so you need PyTorch installed. The CPU build is much smaller and is all the tests need:

pip install numpy pytest nanobind
pip install torch --index-url https://download.pytorch.org/whl/cpu

Then:

python -m pytest tests/python -q      # Python suite, checked against PyTorch

The C++ suite is run through whichever build directory you made above:

ctest --preset release                          # Linux and macOS
ctest --test-dir build/msvc -C Release          # Windows

The Windows form is different for the same reason the build command was: the release preset points at build/release, which the Windows instructions never create, so ctest --preset release there reports "No tests were found!!!" and exits 8.


Troubleshooting

import vkml fails with "libvulkan.so.1: cannot open shared object file" The Vulkan loader is missing. Install it from the table above.

The build stops with "no GLSL compiler found" vkML needs either glslc or glslangValidator to compile its shaders. Install glslang-tools on Debian/Ubuntu, glslang on Fedora or Arch, or shaderc on Arch if you prefer glslc. On Windows and macOS the Vulkan SDK and Homebrew packages above already include one.

vulkan_device_names() returns an empty list vkML installed fine, but the loader found no usable device. Run vulkaninfo --summary to see whether anything can find your GPU. If that is also empty, the problem is your driver, not vkML. On macOS, check that VK_ICD_FILENAMES points at a file that exists.

Your GPU is listed but vkML refuses it The backend needs exactly three Vulkan features: bufferDeviceAddress, scalarBlockLayout and timelineSemaphore. If one is missing, vkML says which one instead of crashing. Run python scripts/hardware_report.py for the details.

CMake cannot find Vulkan on Windows The VULKAN_SDK environment variable is normally set by the SDK installer, but only for terminals opened afterwards — so first close your terminal, open a new one and try again.

If that does not help, check whether it is set at all:

[Environment]::GetEnvironmentVariable('VULKAN_SDK', 'Machine')
[Environment]::GetEnvironmentVariable('VULKAN_SDK', 'User')

On at least one Windows 10 machine with a working SDK at C:\VulkanSDK\1.4.357.0, both come back empty — the installer had not set it at either scope, and "open a new terminal" is advice that cannot succeed. Set it yourself and add the SDK's Bin to PATH so glslc is found too:

$env:VULKAN_SDK = "C:/VulkanSDK/1.4.357.0"
$env:PATH = "$env:VULKAN_SDK/Bin;$env:PATH"

CMake's own error message names the SDK it found and the variable to set, so read it before guessing — it is more specific than this page can be.


Examples

Two complete training scripts, both of which check themselves against PyTorch as they run.

MNIST downloads the dataset for you the first time:

python examples/mnist/train.py          # trains on the GPU, compared to PyTorch

# gui.py only -- train.py needs neither. tkinter is packaged separately on
# most Linux distributions and pip cannot install it; gui.py names the command
# for your distribution if it is missing.
pip install pillow
sudo apt install python3-tk             # Debian/Ubuntu; see gui.py for others
python examples/mnist/gui.py            # draw a digit and watch it predict

CIFAR-100 needs the dataset downloaded by hand, because the site it comes from does not like being scripted at:

# Linux and macOS
mkdir -p examples/cifar100/cache
curl -L https://www.cs.toronto.edu/~kriz/cifar-100-python.tar.gz \
     -o examples/cifar100/cache/cifar-100-python.tar.gz
# Windows. `mkdir -p` is not a thing in cmd.exe -- it fails outright rather than
# creating anything -- and the line continuation is a backtick, not a backslash.
New-Item -ItemType Directory -Force examples\cifar100\cache
curl.exe -L https://www.cs.toronto.edu/~kriz/cifar-100-python.tar.gz `
     -o examples\cifar100\cache\cifar-100-python.tar.gz
python examples/cifar100/train.py

The download is slow and the host throttles hard, so expect it to take a while. If it is interrupted, delete the partial file before retrying — the loader tells you if you forget.

If the archive is missing, the script tells you exactly where to put it.

What these cost on the hardware we have

Not a benchmark — one run each, on one machine, at a tenth of the CIFAR-100 training set. It is here to set expectations before you start something that takes an hour, not to make a claim about vkML against anything else. The rules real measurements follow are in docs/MEASUREMENT-AUDIT.md.

CIFAR-100 CNN, 10 epochs, --train-size 5000, batch 64, run one at a time so nothing competed:

Where Total Per epoch Test accuracy
RX 5600M (discrete, RADV) 24 s 1.46 s 6.03%
Radeon integrated (RENOIR) 104 s 6.16 s 6.03%
PyTorch 2.13 on CPU, 6 threads 51 s 2.57 s 5.30%¹
vkML on CPU not completed 298 s —

The two GPUs agree to the last digit, which is the determinism contract holding across different hardware rather than a coincidence.

The CPU row is the one to read carefully. vkML's CPU backend is the correctness oracle — a naive triple loop, no blocking, no vectorisation and no threading at all — and that is a deliberate decision, written down at src/backend/cpu/kernels_matmul.cpp. It makes the oracle obviously correct and it makes it roughly 100× slower than a tuned CPU framework. A 10-epoch run did not finish in a sitting, so the row is honest about that rather than extrapolated. If you have no usable Vulkan device, read issue #31 before planning around the CPU backend.

¹ The PyTorch run seeds its own weights rather than starting from vkML's, so this column is not a like-for-like accuracy comparison. The example's built-in comparison is what checks the numbers agree, and it does — see How we check correctness.


What is included

Module What it provides
vkml Tensors, 66 operators, dtypes, devices, lazy evaluation
vkml.nn Module, Linear, Conv2d, MaxPool2d, AvgPool2d, BatchNorm2d, LayerNorm, Dropout, Embedding, Conv1d, MultiheadAttention, PositionalEncoding, TransformerEncoderLayer, activations, and the MSE, cross-entropy, BCE-with-logits, KL-divergence and Huber losses
vkml.optim SGD (with momentum), Adam, AdamW, RMSProp
vkml.data Dataset, ArrayDataset, DataLoader, reproducible shuffling, batch transforms (Compose, RandomCrop, RandomHorizontalFlip), split
vkml.serialize Checkpoints stored as a zip of .npy arrays plus JSON metadata

Autograd is reverse-mode, with 47 backward rules. Each rule is written using forward operations, which means gradients reuse the same kernels as the forward pass — so a bug fixed in mul is fixed in the gradient of mul at the same time.

Both f32 and f16 work on either backend. f16 is used for storage only, never for accumulation: values widen to float when they are read and narrow once when written, so a reduction of any length still accumulates in fp32.

Checkpoints cannot execute code

A vkML checkpoint is a zip file containing only data — .npy members read with allow_pickle=False, plus a single JSON document. Neither format can name a function, so loading a model file cannot run a program.

This is a deliberate choice. The well-known problem in this area is model formats built on pickle, which rebuild objects by calling whatever the file names, and we did not want to repeat that.

Decompression bombs are rejected too, before a byte is read. A small archive that expands to an enormous allocation is caught from the zip directory:

vkml.load("suspicious.vkml")
# ValueError: suspicious.vkml expands 1028x (203,998 bytes on disk to
# 209,715,402 in memory), over the 100x limit, and was rejected without being
# read. ...

The limit is an expansion ratio rather than a byte count, because the two populations do not overlap: real checkpoints expand about 1×, real weights asked to compress reach 1.1× — trained weights are high-entropy and barely compress — while an all-zeros bomb reaches over 1000×. A byte cap has no non-arbitrary value, since a 28 GB checkpoint and a 200 KB bomb are both things someone might load.

A pruned model stored densely is mostly zeros and could exceed the limit honestly. Raise it with vkml.load(path, max_expansion_ratio=...); the error says so.


How we check correctness

Every operator is tested against PyTorch, in two stages:

vkml-cpu     vs  PyTorch      catches wrong formulas, axes and broadcast rules
vkml-vulkan  vs  vkml-cpu     catches kernel bugs, against an oracle with identical semantics

Tolerances are worked out from the reduction length in advance, and never widened after a failure. A mismatch is treated as a bug until an error analysis says otherwise.

A green test suite only proves the tests ran, so there are three more checks that ask whether the suite could have failed:

Check The question it answers
scripts/mutation_check.py If we break a kernel on purpose, does a test notice?
scripts/coverage_matrix.py Which operator × dtype × layout combinations are never exercised?
scripts/asan_python.py Does the Python suite pass against an AddressSanitizer build?
python -m pytest tests/python -q        # the validation suite
python scripts/mutation_check.py        # can the suite fail?
python scripts/asan_python.py           # the suite, instrumented

Results are reproducible by design, which we treat as part of correctness rather than a nice extra: no global atomics, fixed reduction trees, and a counter-based RNG that is a pure function of its seed and index.


Project status

Alpha. vkML trains real models and is tested hard, but the GPU evidence comes from two cards plus whatever CI can reach, and it does not cover everything a mature framework does.

What works. The MNIST MLP and CNN and a CIFAR-100 CNN train end to end on the GPU and agree with PyTorch well inside tolerance. 66 operators across both backends. 1,403 Python tests and 115 C++ cases, run against three Vulkan drivers, with CI on Linux and Windows. macOS is not in the push pipeline — see below.

The suite also passes with every device limit clamped to the Vulkan 1.3 guaranteed minimum (VKML_MIN_SPEC=1), which is a stronger statement than passing on the hardware we happen to own: a conformant device may report no more than that, and until recently 592 tests failed under it.

What does not. Listed plainly, because you should find out here rather than half an hour in:

  • Three drivers, and one of them is software. A discrete RX 5600M (RDNA1) and an integrated Renoir iGPU, both under RADV; lavapipe, Mesa's software rasteriser, which has a subgroup size of 8 against RADV's 64 and half the shared memory; and MoltenVK on Apple Silicon. The full suite passes on both RADV GPUs and on lavapipe, and everything except one profiler test passes on MoltenVK. MNIST trains to the same accuracy and the same maximum divergence from PyTorch on both GPUs. There is no evidence at all about NVIDIA, Intel, Qualcomm or ARM — those are the reports we would most like to see.
  • macOS is not a supported platform yet. It has been probed, not adopted: the job reached 1,233 passing tests on a GitHub runner, and one test cannot pass there because that runner's virtualised GPU reports working timestamps and never advances them. Rather than leave a permanently red job on every push, it now lives in .github/workflows/macos-moltenvk.yml and runs only on request (gh workflow run macos-moltenvk.yml). Treat macOS as untested until it comes back into the main pipeline.
  • What each platform actually proves. Linux is the real test; every job runs there. Windows compiles under MSVC and passes the C++ suite, but the runner has no GPU, so nothing Vulkan is exercised there. The macOS job, when run by hand, exercises MoltenVK on an Apple Paravirtual device in a VM rather than physical Apple hardware; GPU timestamps do not advance there, so the profiler cannot be used on that runner. Validation layers are clean on it.
  • Vulkan is all-or-nothing, by design rather than by omission — see Choosing a device. If the GPU cannot run an operator, vkML raises instead of silently moving that work to the CPU. Two cases exist today: prod. It is listed here as well as there because it is a real limit on what vkML can run, whatever the reasoning behind it.
  • Missing layers: Conv3d, gradient checkpointing. python scripts/check_module_coverage.py generates this list from the API rather than restating it — 30 of the manifesto's 34 P1 modules are present.
  • Tensors are limited to rank 4. This is a deliberate push-constant budget decision, not an oversight.
  • f16 matmul is correct but slower than f32, because the vectorised tile load is f32-only for now.
  • No distributed training, no quantisation, no ONNX.

If you have hardware we do not

That list is short because it was written by someone with two GPUs. If you have anything else — NVIDIA, Intel, Qualcomm, ARM, Apple, or Windows — a single command tells us both whether vkML runs on it:

python scripts/hardware_report.py --run-tests

It describes every Vulkan device it can find and runs the validation suite against the ones it can use. It is written to work even on a device vkML cannot use, which is the report we most want: if your device is rejected, it tells you which of the three required features is missing instead of crashing. Please paste the output into an issue.


Documentation

Design decisions are kept together with the reasoning behind them, including the alternatives that were rejected and why:

Document What is in it
docs/ARCHITECTURE.md Layering, the graph IR, the backend interface, and the forks taken along the way
docs/THEORY.md The numerics: error bounds, pairwise summation, stability
docs/adr/ Decisions that are expensive to reverse — graph ownership, the allocator, dtype promotion
docs/MEASUREMENT-AUDIT.md How performance is measured, and which instruments lie
docs/PERFORMANCE-MODEL.md What the hardware can do, and what the kernels achieve

Contributing

Bug reports, and especially reports from hardware we do not have, are the main way device-specific assumptions get found. CONTRIBUTING.md covers what to put in an issue, how changes are proposed and reviewed, and what to run before pushing.

If you are reporting a bug, python scripts/hardware_report.py produces the device details that make a report reproducible.

Working with an AI assistant? CLAUDE.md is a short orientation map — build commands, the layout, the layering rule, and the traps that have already cost somebody an afternoon. Claude Code loads it automatically; for any other tool, point it there first. The standards it routes to live in .claude/skills/cpp_spec/, which is the engineering constitution this repository is held to, tracked in git so a clone is complete.


License

vkML is licensed under the Apache License 2.0. See LICENSE and NOTICE.

Releases

Packages

Contributors

Languages