computeml
Run ML inference and training on any GPU from Python, through Vulkan compute shaders. You work with NumPy arrays. The wheel ships the compiled library, so you only need NumPy and a Vulkan driver.
Install
pip install computeml
uv add computeml
Requirements:
- Linux x86_64 (glibc 2.27 or newer) and Python 3.10 or newer.
- A Vulkan driver. NVIDIA, AMD and Intel GPU drivers include one. With no GPU, Mesa lavapipe
runs on the CPU:
apt install mesa-vulkan-drivers.
Quickstart
import numpy as np
import computeml as cml
ctx = cml.Context()
print(ctx.device_name)
a = ctx.asarray(np.random.rand(512, 256))
b = ctx.asarray(np.random.rand(256, 128))
c = cml.ops.relu(a @ b) * 2.0
print(c.shape, c.numpy()[0, :4])
ctx.asarray copies an array to the GPU. Ops queue work on the GPU. .numpy() waits for the
work and copies the result back.
Coming from NumPy, PyTorch or CuPy
| You know | In computeml |
|---|---|
cp.asarray(x), torch.as_tensor(x) |
ctx.asarray(x) |
np.zeros, ones, full, empty |
ctx.zeros(shape), ctx.ones, ctx.full, ctx.empty |
a + b, a * 2, a @ b, -a |
the same |
.shape, .dtype, .ndim, .size |
the same |
t.cpu().numpy(), cp.asnumpy(t) |
t.numpy() |
torch.nn.functional.layer_norm |
cml.ops.layer_norm |
torch.nn.Linear(16, 32) |
cml.nn.Linear(ctx, 16, 32) |
loss.backward(), w.grad, torch.optim.AdamW |
the same, cml.optim.AdamW |
Differences you will meet:
- No broadcasting. Shapes must match element for element, or the op raises
ValueError. - float32 only for inputs and outputs.
asarrayconverts ints and float64 to float32. tensor + numberis not supported yet.tensor * numberandtensor / numberwork.np.asarray(tensor)raisesTypeError. Call.numpy(), so every GPU-to-CPU copy is visible.- Every layer takes the
Contextfirst. There is no default device.
Layers
import numpy as np
import computeml as cml
ctx = cml.Context()
model = cml.nn.Sequential(
cml.nn.Linear(ctx, 16, 32, activation="gelu"),
cml.nn.Linear(ctx, 32, 8),
cml.nn.LayerNorm(ctx, 8),
)
x = ctx.asarray(np.random.rand(4, 16))
print(model(x).numpy().shape)
Linear weights use the PyTorch layout (out, in). Load trained weights with
cml.nn.Linear.from_numpy(ctx, weight, bias).
Training
import numpy as np
import computeml as cml
ctx = cml.Context()
X = np.random.rand(128, 4)
y = (X.sum(axis=1) > 2).astype(np.float32)
model = cml.nn.Sequential(
cml.nn.Linear(ctx, 4, 16, activation="relu"),
cml.nn.Linear(ctx, 16, 2),
).requires_grad_()
opt = cml.optim.AdamW(model.parameters(), lr=0.05)
x, t = ctx.asarray(X), ctx.asarray(y)
for _ in range(100):
opt.zero_grad()
loss = cml.ops.cross_entropy(model(x), t)
loss.backward()
opt.step()
print(float(loss))
Gradients are computed on the GPU by the C library's autograd tape. See the training guide for which ops can be trained.
Fused ops
One kernel does the work of several ops, so the data is read from GPU memory once.
import numpy as np
import computeml as cml
ctx = cml.Context()
x = ctx.asarray(np.random.rand(8, 64))
w = ctx.asarray(np.random.rand(128, 64))
b = ctx.asarray(np.random.rand(128))
y = cml.ops.linear(x, w, b, activation="gelu") # gelu(x @ w.T + b), one kernel
print(y.shape)
cml.ops also has softmax, layer and RMS norm, flash attention (multi-head, causal), RoPE,
embeddings, permute, concat and reductions. See
ops.py.
Capture and replay
ctx.capture records a function's GPU work on the first call. Later calls resubmit the
recorded work with new input values, with no Python per op.
import numpy as np
import computeml as cml
ctx = cml.Context()
w = ctx.asarray(np.random.rand(64, 64))
@ctx.capture
def step(x):
return cml.ops.relu(x @ w)
for _ in range(3):
y = step(np.random.rand(32, 64))
print(y.numpy().sum())
print(step.record_count) # 1: recorded once, replayed twice
The output is the same tensor on every call, so read it before the next call. Any other op on the context in between makes the next call record again.
Quantized weights
import numpy as np
import computeml as cml
ctx = cml.Context()
x = ctx.asarray(np.random.rand(16, 256))
w = ctx.asarray(np.random.rand(256, 64)).quantize("Q8_0")
print((x @ w).numpy().shape) # w is dequantized inside the matmul kernel
Errors and logs
cml.NoDeviceError: no Vulkan driver or GPU. The message says what to install.ImportErroronimport computeml: the Vulkan loaderlibvulkan.so.1is missing.ValueError/TypeError: a wrong shape or dtype, raised before any GPU work.- Set
CML_LOG=1to print the chosen GPU and kernel class to stderr. - Set
CML_GPU_INDEX=1to use the second GPU.
Build from source
Set COMPUTEML_LIB to use your own libcomputeml.so. To build it and run the tests from a
checkout of the repo:
cmake -B build -S . && cmake --build build --target computeml_shared
cd python && uv run --with pytest python -m pytest -q
A BERT-tiny example lives in
examples/python/bert_tiny.py.
Metadata
Release files for computeml 0.3.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| computeml-0.3.0-py3-none-manylinux_2_27_x86_64.whl | Python 3 | none | Linux glibc 2.27+ x86-64 | Details |
Release files / computeml-0.3.0-py3-none-manylinux_2_27_x86_64.whl
| Download URL | computeml-0.3.0-py3-none-manylinux_2_27_x86_64.whl |
|---|---|
| Size | 348.2 kB |
| Tags | Linux glibc 2.27+ x86-64 Python 3 |
|
SHA-256 checksum How to use checksums |
69554559c4a9b5890a72cb034c1c19ba81b9d58171965914a261fefb5190c725
|
|
BLAKE2b-256 checksum How to use checksums |
376f0d5e0567c142d9874123c5912e7a8d4d291384efbba8ffb74121804661c0
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.9.30 {"installer":{"name":"uv","version":"0.9.30","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Debian GNU/Linux","version":"12","id":"bookworm","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Security for computeml 0.3.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.