A C++ deep learning library with Vulkan GPU acceleration, exposed to Python
Project description
wefml
C++ deep learning library with optional CUDA and Vulkan GPU acceleration, packaged for Python via pip.
Features
- Tensor class with full arithmetic and numpy interop
- Matrix ops: matmul, transpose, softmax, argmax, relu, sigmoid, reducesum, positional encoding
- Sequential and functional model building
- Tokenizer: English/Spanish tab-separated tokenizer
- MNIST loader: IDX format image/label loader
- GPU toggle: one flag switches between CPU and GPU layers
- Dual GPU backend: CUDA (preferred) or Vulkan, auto-detected at build time
Installation
Prerequisites
- Python >= 3.8
- CMake >= 3.15
- A C++17 compiler (g++, clang++)
- pybind11 (
pip install pybind11) - (Optional) CUDA Toolkit for CUDA GPU support (preferred)
- (Optional) Vulkan SDK for Vulkan GPU support (fallback)
If neither CUDA nor Vulkan is found, the library builds in CPU-only mode automatically. GPU layers won't be available but everything else works.
Quick Start
import wefml
import numpy as np
# Check GPU availability
print(wefml.gpu_backend()) # 'cuda', 'vulkan', or 'none'
print(wefml.is_cuda_available())
print(wefml.is_vulkan_available())
# Tensors
a = wefml.Tensor.from_numpy(np.random.randn(2, 3).astype(np.float32))
b = wefml.Tensor.from_numpy(np.random.randn(3, 4).astype(np.float32))
c = wefml.ops.matmul(a, b)
print(c.numpy())
d = wefml.ops.transpose(a)
e = wefml.ops.softmax(c)
f = wefml.ops.relu(c)
Sequential Model
import wefml
model = wefml.Model([
wefml.Linear(128, use_bias=True),
wefml.ReLU(),
wefml.Linear(10, use_bias=True),
])
model.fit(labels, inputs, epochs=10, lr=0.01)
pred = model.predict(test_inputs)
model.summary()
Functional Model (Transformer Example)
The functional API uses .call() to chain layers with explicit control over data flow, which is needed for architectures like transformers where layers have multiple inputs.
import wefml
# wefml.use_gpu(True)
tok = wefml.Tokenizer()
tok.process("english_spanish_tab.txt", early_stop=4000)
d_model = 64
embedding = wefml.Embedding(tok.english_vsize, d_model)
embedding_out = wefml.Embedding(tok.spanish_vsize, d_model)
mha = wefml.MHA(d_model, self_attention=True, num_heads=4, use_bias=True, use_mask=True)
cross_attn = wefml.MHA(d_model, self_attention=False, num_heads=4, use_bias=True, use_mask=True)
ffn = wefml.Linear(d_model, use_bias=True)
out = wefml.Linear(tok.spanish_vsize, use_bias=True)
norm = wefml.LayerNorm(2)
relu = wefml.ReLU()
In the C++ codebase, the transformer uses the functional API like this:
// Functional model: layers are called explicitly with .call()
ValLayer x = {nullptr, &enc_input};
x = embedding.call(x, training, gpu);
// self attention
ValLayer c = mha_input.call(x, x, x, training, gpu, {nullptr, &enc_mask});
// add and norm
temp = *c.val + *x.val;
x.val = &temp;
x = norm.call(x, training, gpu);
// feed forward
c = ffn.call(x, training, gpu);
c = relu.call(c, training, gpu);
// output layer
e = out.call(x_out, training, gpu);
GPU Mode
The build system auto-detects the GPU backend at compile time:
- CUDA is preferred when the CUDA toolkit is available (faster, NVIDIA GPUs)
- Vulkan is the fallback when CUDA is not found but Vulkan SDK is available (cross-platform)
- CPU-only when neither is available
Only one GPU backend is compiled since both implement the same class interfaces.
import wefml
print(wefml.gpu_backend()) # check which backend was compiled
wefml.use_gpu(True)
# Layer constructors automatically use GPU variants:
# Linear() -> LinearGPU
# Conv2D() -> Conv2DGPU
# MaxPool2D() -> MaxPool2DGPU
model = wefml.Model([
wefml.Conv2D(3, 3, 128, use_bias=True),
wefml.ReLU(),
wefml.MaxPool2D(2, 2),
wefml.Flatten(),
wefml.Linear(10, use_bias=True),
], use_gpu=True)
API Reference
GPU config
wefml.use_gpu(enable: bool)-- toggle GPU acceleration globallywefml.is_gpu_available()-- True if any GPU support was compiled inwefml.is_cuda_available()-- True if CUDA was compiled inwefml.is_vulkan_available()-- True if Vulkan was compiled inwefml.gpu_backend()-- returns'cuda','vulkan', or'none'
Tensor
Tensor.from_numpy(arr)-- create from numpyTensor.zeros(shape)/Tensor.create(shape)-- create empty.numpy()-- convert to numpy.shape,.rank,.size+,-,*,/with other Tensors or scalars
Ops (wefml.ops)
.matmul(a, b),.matmul_mt(a, b, threads).transpose(a),.argmax(a),.softmax(a).relu(a),.sigmoid(a),.reducesum(a, axis).positional_encoding(length, depth).l2(a, b),.binarycrossentropy(a, b)
Layers
Linear(units, use_bias, seed)-- dense layer, GPU variant auto-selectedConv2D(kh, kw, units, use_bias, seed)-- 2D convolution, GPU variant auto-selectedMaxPool2D(kh, kw)-- max pooling, GPU variant auto-selectedReLU()-- rectified linear activationSigmoid()-- sigmoid activationFlatten()-- flatten to 1DLayerNorm(axis, eps)-- layer normalizationReduceSum(axis, keepdims)-- sum reduction along axisEmbedding(vocab_size, d_model, seed)-- token embedding lookupMHA(d_model, self_attn, num_heads, use_bias, use_mask, use_gpu)-- multi-head attention
Model
Sequential: wefml.Model(layers, use_gpu)
.add(layer).fit(labels, inputs, val_labels, val_inputs, epochs, lr, batch_size, loss_fn).predict(inputs).summary()
Functional: layers have a .call() method for explicit wiring (used in transformers and other non-sequential architectures).
Data
wefml.Tokenizer()--.process(path, early_stop)wefml.load_mnist_images(path, max_items)wefml.load_mnist_labels(path, max_items)
Building
The pip build uses scikit-build-core + pybind11 + CMake. When you run pip install ., it:
- Compiles all C++ sources with pybind11 bindings
- Detects CUDA first; if not found, detects Vulkan; links the available backend
- Installs the
wefmlPython package with the native_learnn_coreextension
License
MIT
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
File details
Details for the file wefml-0.1.3.tar.gz.
File metadata
- Download URL: wefml-0.1.3.tar.gz
- Upload date:
- Size: 2.9 MB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.0
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
556024b201193c8933685599fb75173f61e9c7977043e538d71fc1953f6bd7f1
|
|
| MD5 |
74247601049b625076b1ed2fcfebe0c2
|
|
| BLAKE2b-256 |
8611c6b8195289b7467d56f55f9dd77eb8b54dd3437b392a712ac22cfed78493
|