vkML 0.1.0

Tensor

A handle to a value in the computation graph.

Cheap to copy. Two Tensors sharing a node are two names for one value, as in PyTorch — copying a Tensor copies a handle, never the data.

A Tensor is not necessarily computed yet. Operations build graph nodes and evaluation is deferred until something observes the data (to_host, item, backward) or realize() is called. Eager mode collapses that distinction while debugging.

The graph node type is not visible through the public API: Node is a forward declaration only, so callers and the binding layer see an opaque handle and the internal representation can change without breaking either. That is a recorded guardrail, not an implementation accident.

Layout is row-major: shape()[0] is the outermost axis, matching NumPy, PyTorch and DLPack. strides() reports bytes, as NumPy does — the DLPack bridge converts to element strides at the boundary and nowhere else.

Construction

Tensor

Tensor(const Tensor&);include/vkml/api/tensor.h:40
Tensor(Tensor&&) noexcept;include/vkml/api/tensor.h:42
explicit Tensor(std::shared_ptr<Node> node);include/vkml/api/tensor.h:46

Wraps an existing graph node. Internal; not part of the stable surface.

full

[[nodiscard]] static Tensor full(std::span<const int64_t> dims, double value, DType dtype = DType::F32, Device device = Device::cpu());include/vkml/api/tensor.h:51
[[nodiscard]] static Tensor full(std::initializer_list<int64_t> dims, double value, DType dtype = DType::F32, Device device = Device::cpu())include/vkml/api/tensor.h:74
return full(std::span<const int64_t>{dims.begin(), dims.size()}, value, dtype, device);include/vkml/api/tensor.h:75

zeros

[[nodiscard]] static Tensor zeros(std::span<const int64_t> dims, DType dtype = DType::F32, Device device = Device::cpu());include/vkml/api/tensor.h:54
[[nodiscard]] static Tensor zeros(std::initializer_list<int64_t> dims, DType dtype = DType::F32, Device device = Device::cpu())include/vkml/api/tensor.h:79
return zeros(std::span<const int64_t>{dims.begin(), dims.size()}, dtype, device);include/vkml/api/tensor.h:80

ones

[[nodiscard]] static Tensor ones(std::span<const int64_t> dims, DType dtype = DType::F32, Device device = Device::cpu());include/vkml/api/tensor.h:57
[[nodiscard]] static Tensor ones(std::initializer_list<int64_t> dims, DType dtype = DType::F32, Device device = Device::cpu())include/vkml/api/tensor.h:84
return ones(std::span<const int64_t>{dims.begin(), dims.size()}, dtype, device);include/vkml/api/tensor.h:85

arange

[[nodiscard]] static Tensor arange(double start, double stop, double step = 1.0, DType dtype = DType::F32, Device device = Device::cpu());include/vkml/api/tensor.h:60

from_host

[[nodiscard]] static Tensor from_host(const void* data, std::span<const int64_t> dims, DType dtype = DType::F32, Device device = Device::cpu());include/vkml/api/tensor.h:64
[[nodiscard]] static Tensor from_host(const void* data, std::initializer_list<int64_t> dims, DType dtype = DType::F32, Device device = Device::cpu())include/vkml/api/tensor.h:89
return from_host(data, std::span<const int64_t>{dims.begin(), dims.size()}, dtype, device);include/vkml/api/tensor.h:90

Copies nbytes of host data into a new tensor.

Shape and layout

shape

[[nodiscard]] std::vector<int64_t> shape() const;include/vkml/api/tensor.h:97

strides

[[nodiscard]] std::vector<int64_t> strides() const;include/vkml/api/tensor.h:106

In bytes, not elements, matching NumPy. A stride may be 0, which is how broadcasting is represented.

size

[[nodiscard]] int64_t size(int axis) const;include/vkml/api/tensor.h:103

ndim

[[nodiscard]] int ndim() const;include/vkml/api/tensor.h:99

numel

[[nodiscard]] int64_t numel() const;include/vkml/api/tensor.h:101

dtype

[[nodiscard]] DType dtype() const;include/vkml/api/tensor.h:108

device

[[nodiscard]] Device device() const;include/vkml/api/tensor.h:110

is_contiguous

[[nodiscard]] bool is_contiguous() const;include/vkml/api/tensor.h:112

defined

[[nodiscard]] bool defined() const noexcept { return node_ != nullptr; }include/vkml/api/tensor.h:95

Whether this handle refers to a value at all. A default-constructed Tensor and an uncomputed .grad are both undefined.

Views — no copy

reshape

[[nodiscard]] Tensor reshape(std::span<const int64_t> dims) const;include/vkml/api/tensor.h:130
[[nodiscard]] Tensor reshape(std::initializer_list<int64_t> dims) constinclude/vkml/api/tensor.h:138
return reshape(std::span<const int64_t>{dims.begin(), dims.size()});include/vkml/api/tensor.h:139

A view. Reinterprets the same storage with new extents; the element count must be unchanged. No copy, so mutating either handle's storage is visible through both.

permute

[[nodiscard]] Tensor permute(std::span<const int> perm) const;include/vkml/api/tensor.h:131
[[nodiscard]] Tensor permute(std::initializer_list<int> perm) constinclude/vkml/api/tensor.h:142
return permute(std::span<const int>{perm.begin(), perm.size()});include/vkml/api/tensor.h:143

A view. Reorders axes by permuting the stride vector, so the data is untouched and the result is usually non-contiguous.

transpose

[[nodiscard]] Tensor transpose(int a, int b) const;include/vkml/api/tensor.h:132

A view. permute restricted to swapping two axes.

squeeze

[[nodiscard]] Tensor squeeze(int axis) const;include/vkml/api/tensor.h:133

A view. Drops an axis of extent 1.

unsqueeze

[[nodiscard]] Tensor unsqueeze(int axis) const;include/vkml/api/tensor.h:134

A view. Inserts an axis of extent 1.

slice

[[nodiscard]] Tensor slice(int axis, int64_t start, int64_t stop, int64_t step = 1) const;include/vkml/api/tensor.h:135

A view. Adjusts the offset and extents, and the stride when step is greater than 1. The result shares storage with the original.

broadcast_to

[[nodiscard]] Tensor broadcast_to(std::span<const int64_t> dims) const;include/vkml/api/tensor.h:136
[[nodiscard]] Tensor broadcast_to(std::initializer_list<int64_t> dims) constinclude/vkml/api/tensor.h:146
return broadcast_to(std::span<const int64_t>{dims.begin(), dims.size()});include/vkml/api/tensor.h:147

A view. Expanded axes are given stride 0, so the same element is re-read rather than duplicated — which is why broadcasting costs no memory anywhere in vkML.

Copies

contiguous

[[nodiscard]] Tensor contiguous() const;include/vkml/api/tensor.h:153

Materialises a contiguous copy, and returns *this unchanged when the tensor already is contiguous — so calling it defensively is free on the common path.

to

[[nodiscard]] Tensor to(DType dtype) const;include/vkml/api/tensor.h:155

Converts dtype, allocating a new tensor.

assign_

void assign_(const Tensor& src);include/vkml/api/tensor.h:171

Overwrites this tensor's storage in place — the one deliberate escape from the otherwise functional graph.

It exists for exactly one reason: optimisers must update parameters that modules already hold references to. Rebinding a new Tensor would leave every Module still pointing at the old one, so PyTorch mutates in place and so does this.

Hazard: any already-computed node that read this tensor keeps its old result, while any node computed afterwards sees the new values. That is harmless in the intended use — the training graph is rebuilt each step — but assign_ must not be used mid-graph. Requires matching shape, dtype and device, and a contiguous destination.

Observation

to_host

void to_host(void* dst) const;include/vkml/api/tensor.h:123

Copies the contents out to host memory. Forces realization.

item

[[nodiscard]] float item() const;include/vkml/api/tensor.h:126

The value of a single-element tensor. Forces realization and a device-to-host copy.

str

[[nodiscard]] std::string str() const;include/vkml/api/tensor.h:114

Autograd

requires_grad

[[nodiscard]] bool requires_grad() const;include/vkml/api/tensor.h:175

set_requires_grad

void set_requires_grad(bool value);include/vkml/api/tensor.h:179

Marks a leaf as trainable. Throws for non-float dtypes and for non-leaves, matching PyTorch.

grad

[[nodiscard]] Tensor grad() const;include/vkml/api/tensor.h:182

The accumulated gradient, or an undefined tensor when none has been computed. Check defined() before using it.

set_grad

void set_grad(const Tensor& g);include/vkml/api/tensor.h:184

realize

const Tensor& realize() const;include/vkml/api/tensor.h:119

Runs the graph this tensor is the root of. See realize.

Internals

node

[[nodiscard]] const std::shared_ptr<Node>& node() const noexcept { return node_; }include/vkml/api/tensor.h:187

Internal accessor for layers above the API boundary.

Other members

operator=

Tensor& operator=(const Tensor&);include/vkml/api/tensor.h:41
Tensor& operator=(Tensor&&) noexcept;include/vkml/api/tensor.h:43

~Tensor

See also tensor, realize, backward, detach

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