vkML 0.1.0

Arithmetic

7 functions — 7 documented.

add

add(arg0: Tensor, arg1: Tensor, /) → Tensor
CPUVulkan

Element-wise addition.

Shapes are broadcast by NumPy rules. Broadcasting is implemented by giving the expanded axes stride 0 rather than by materialising a copy — Shape holds strides in bytes and permits 0, so a broadcast operand re-reads the same element instead of allocating an expanded one.

Parameters

input (Tensor)
The left operand.
other (Tensor)
The right operand, broadcastable against input.

Returns

A tensor of the broadcast shape.

ⓘ Note

Exact: the two backends agree bit for bit, so the test suite compares them with no tolerance at all.

Example

>>> a = vkml.tensor(np.array([1.0, 2.0], dtype=np.float32))
>>> b = vkml.tensor(np.array([[10.0], [20.0]], dtype=np.float32))
>>> vkml.add(a, b).numpy()
array([[11., 12.],
       [21., 22.]], dtype=float32)

Implementation

Declared ininclude/vkml/api/ops.h:12
Graph nodeOpKind::Add
CPU kernelsrc/backend/cpu/kernels_elementwise.cpp:241
Vulkan shadershaders/binary.comp (132 lines · 3 specialisation constants)
Gradient ruleautograd.cpp:192
Historycommits touching the CPU kernel
Tests (≥4)test_f16.py test_nan_semantics.py test_ops_vs_torch.py

See also sub, mul, maximum

sub

sub(arg0: Tensor, arg1: Tensor, /) → Tensor
CPUVulkan

Element-wise subtraction, input − other.

Shapes are broadcast by NumPy rules. Broadcasting is implemented by giving the expanded axes stride 0 rather than by materialising a copy — Shape holds strides in bytes and permits 0, so a broadcast operand re-reads the same element instead of allocating an expanded one.

Parameters

input (Tensor)
The left operand.
other (Tensor)
The right operand, broadcastable against input.

Returns

A tensor of the broadcast shape.

ⓘ Note

Exact on both backends.

Example

>>> vkml.sub(vkml.tensor(np.array([5.0, 3.0], dtype=np.float32)),
...           vkml.tensor(np.array([2.0, 1.0], dtype=np.float32))).numpy()
array([3., 2.], dtype=float32)

Implementation

Declared ininclude/vkml/api/ops.h:13
Graph nodeOpKind::Sub
CPU kernelsrc/backend/cpu/kernels_elementwise.cpp:245
Vulkan shadershaders/binary.comp (132 lines · 3 specialisation constants)
Gradient ruleautograd.cpp:197
Historycommits touching the CPU kernel
Tests (≥3)test_ops_vs_torch.py

See also add, neg

mul

mul(arg0: Tensor, arg1: Tensor, /) → Tensor
CPUVulkan

Element-wise multiplication.

Shapes are broadcast by NumPy rules. Broadcasting is implemented by giving the expanded axes stride 0 rather than by materialising a copy — Shape holds strides in bytes and permits 0, so a broadcast operand re-reads the same element instead of allocating an expanded one.

Parameters

input (Tensor)
The left operand.
other (Tensor)
The right operand, broadcastable against input.

Returns

A tensor of the broadcast shape.

ⓘ Note

Exact on both backends.

Example

>>> vkml.mul(vkml.tensor(np.array([2.0, 3.0], dtype=np.float32)),
...           vkml.tensor(np.array([4.0, 5.0], dtype=np.float32))).numpy()
array([ 8., 15.], dtype=float32)

Implementation

Declared ininclude/vkml/api/ops.h:14
Graph nodeOpKind::Mul
CPU kernelsrc/backend/cpu/kernels_elementwise.cpp:261
Vulkan shadershaders/binary.comp (132 lines · 3 specialisation constants)
Gradient ruleautograd.cpp:202
DecisionsADR 0013
Benchmarkedmul
Historycommits touching the CPU kernel
Tests (≥18)test_device_limits.py test_nan_semantics.py test_nn_vs_torch.py test_ops_vs_torch.py test_vulkan_kernels.py

See also div, add, square

div

div(arg0: Tensor, arg1: Tensor, /) → Tensor
CPUVulkan

Element-wise division, input / other.

IEEE division throughout: x/0 is ±inf and 0/0 is NaN, rather than raising.

Shapes are broadcast by NumPy rules. Broadcasting is implemented by giving the expanded axes stride 0 rather than by materialising a copy — Shape holds strides in bytes and permits 0, so a broadcast operand re-reads the same element instead of allocating an expanded one.

Parameters

input (Tensor)
The left operand.
other (Tensor)
The right operand, broadcastable against input.

Returns

A tensor of the broadcast shape.

Example

>>> vkml.div(vkml.tensor(np.array([1.0, 0.0], dtype=np.float32)),
...           vkml.tensor(np.array([2.0, 0.0], dtype=np.float32))).numpy()
array([0.5, nan], dtype=float32)

Implementation

Declared ininclude/vkml/api/ops.h:15
Graph nodeOpKind::Div
CPU kernelsrc/backend/cpu/kernels_elementwise.cpp:265
Vulkan shadershaders/binary.comp (132 lines · 3 specialisation constants)
Gradient ruleautograd.cpp:235
Historycommits touching the CPU kernel
Tests (≥1)test_ops_vs_torch.py

See also mul, reciprocal

pow

pow(arg0: Tensor, arg1: Tensor, /) → Tensor
CPUVulkan

Element-wise power, input ** other.

Matches std::pow, not GLSL's pow. GLSL leaves pow(x, y) explicitly undefined for x < 0, while std::pow is defined there whenever y is an integer — std::pow(-2, 3) is -8, not NaN. Leaving the built-in to handle it would make the two backends disagree on a case the CPU answers perfectly well, so the shader peels the sign off and reapplies it.

Shapes are broadcast by NumPy rules. Broadcasting is implemented by giving the expanded axes stride 0 rather than by materialising a copy — Shape holds strides in bytes and permits 0, so a broadcast operand re-reads the same element instead of allocating an expanded one.

Parameters

input (Tensor)
The left operand.
other (Tensor)
The right operand, broadcastable against input.

Returns

A tensor of the broadcast shape.

Example

>>> vkml.pow(vkml.tensor(np.array([-2.0, 2.0], dtype=np.float32)),
...           vkml.tensor(np.array([3.0, 3.0], dtype=np.float32))).numpy()
array([-8.,  8.], dtype=float32)

In the Vulkan kernel

float pow_op(float x, float y)shaders/binary.comp:73

pow matching std::pow, which the CPU kernel uses.

GLSL's pow(x, y) is explicitly undefined for x < 0, but std::pow is defined there whenever y is an integer -- std::pow(-2, 3) is -8, not NaN. Leaving the built-in to handle it would make the two backends disagree on a case the CPU answers perfectly well, so the sign is peeled off and reapplied.

Implementation

Declared ininclude/vkml/api/ops.h:16
Graph nodeOpKind::Pow
CPU kernelsrc/backend/cpu/kernels_elementwise.cpp:269
Vulkan shadershaders/binary.comp (132 lines · 3 specialisation constants)
Gradient ruleautograd.cpp:242
Historycommits touching the CPU kernel
Tests (≥5)test_autograd_vs_torch.py test_ops_vs_torch.py test_vulkan_kernels.py

See also square, sqrt, exp

maximum

maximum(arg0: Tensor, arg1: Tensor, /) → Tensor
CPUVulkan

Element-wise maximum of two tensors.

NaN propagates, matching torch.maximum. GLSL's max() is undefined for NaN and std::fmax returns the non-NaN operand, so the shader tests for NaN explicitly and returns a quiet NaN written from its bit pattern — not 0.0/0.0, which the compiler is free to constant-fold or treat as undefined.

This is tested as exact, so the difference is not academic.

Shapes are broadcast by NumPy rules. Broadcasting is implemented by giving the expanded axes stride 0 rather than by materialising a copy — Shape holds strides in bytes and permits 0, so a broadcast operand re-reads the same element instead of allocating an expanded one.

Parameters

input (Tensor)
The left operand.
other (Tensor)
The right operand, broadcastable against input.

Returns

A tensor of the broadcast shape.

Example

>>> vkml.maximum(vkml.tensor(np.array([1.0, float('nan')], dtype=np.float32)),
...               vkml.tensor(np.array([2.0, 5.0], dtype=np.float32))).numpy()
array([ 2., nan], dtype=float32)

Implementation

Declared ininclude/vkml/api/ops.h:17
Graph nodeOpKind::Maximum
CPU kernelsrc/backend/cpu/kernels_elementwise.cpp:273
Vulkan shadercomposed, or dispatched through a shared kernel
Gradient ruleautograd.cpp:253
Historycommits touching the CPU kernel
Tests (≥1)test_nan_semantics.py

See also minimum, clamp_min, amax, relu

minimum

minimum(arg0: Tensor, arg1: Tensor, /) → Tensor
CPUVulkan

Element-wise minimum of two tensors.

NaN propagates, by the same explicit test as maximum.

Shapes are broadcast by NumPy rules. Broadcasting is implemented by giving the expanded axes stride 0 rather than by materialising a copy — Shape holds strides in bytes and permits 0, so a broadcast operand re-reads the same element instead of allocating an expanded one.

Parameters

input (Tensor)
The left operand.
other (Tensor)
The right operand, broadcastable against input.

Returns

A tensor of the broadcast shape.

Example

>>> vkml.minimum(vkml.tensor(np.array([1.0, float('nan')], dtype=np.float32)),
...               vkml.tensor(np.array([2.0, 5.0], dtype=np.float32))).numpy()
array([ 1., nan], dtype=float32)

Implementation

Declared ininclude/vkml/api/ops.h:18
Graph nodeOpKind::Minimum
CPU kernelsrc/backend/cpu/kernels_elementwise.cpp:283
Vulkan shadercomposed, or dispatched through a shared kernel
Gradient ruleautograd.cpp:258
Historycommits touching the CPU kernel
Testsnone found by name

See also maximum, clamp_max, amin

vkML — Vulkan-first machine learning in C++20. Apache-2.0. Signatures on this page are generated from the installed module.