Basics of VTensor#
Create tensors on GPU#
VTensor offers several generators to create tensors on a GPU device. If the user does not specify the data type, the default data type is float. The following code snippet demonstrates how to create tensors with different values.
#include <lib/vtensor.hpp>
int main() {
auto a = vt::arange(10); // Create a tensor with values from 0 to 9
auto b = vt::ones(10); // Create a tensor with all elements as 1
auto c = vt::zeros(10); // Create a tensor with all elements as 0
auto d = vt::eye(3); // Create a 3x3 identity matrix
auto e = vt::zeros<int>(10, 10); // Create a 2D tensor with all elements as 0
auto f = vt::ones<bool>(10, 10); // Create a 2D tensor with all elements as True
vt::print(f); // Print the tensor
}
Basics operations#
Users could also do a variety of operations on tensors, such as addition, subtraction, multiplication, and division.
#include <lib/vtensor.hpp>
int main() {
auto a = vt::arange(10); // Create a tensor with values from 0 to 9
auto b = vt::ones(10); // Create a tensor with all elements as 1
a += 1.0f; // Add 1 to each element
b = b + a; // Add tensor a to tensor b
b = b * 2.0f; // Multiply each element by 2
vt::print(b); // Print the tensor
}
VTensor also supports reshape and slice operations without copying the data. The index [] operator performs slicing along the last axis and reduces the tensor’s dimension by one. The bracket ({start, stop, step}) operator performs a slice operation along the specified axes and returns a tensor with the same dimension as the original tensor. Notice that the slicing operation will make the tensor’s memory non-contiguous. Some of the functions (e.g. CuBLAS, CuSolver) might require a contiguous memory layout. In such cases, the tensor will be copied to a contiguous memory layout.
#include <lib/vtensor.hpp>
int main() {
auto a = vt::arange(12).reshape(2, 2, 3); // Create a 3D tensor.
auto b = b[0]; // Slice along the first axis, resulting in a 2x3 tensor.
b = a({0, 2, 1}, {0, 2, 2}); // Slice along the first and second axes, resulting in a 2x1 tensor.
vt::print(b); // Print the tensor
}
Just like numpy, VTensor offers support for broadcasting operations as well. Broadcasting occurs when two tensors have mismatched dimensions; the smaller tensor is expanded to match the shape of the larger tensor. Below is a code example illustrating how to execute broadcasting operations
#include <lib/vtensor.hpp>
int main() {
auto tensor1 = vt::arange(12).reshape(1, 2, 3);
auto tensor2 = vt::arange(2).reshape(2, 1, 1);
auto tensor3 = tensor1 + tensor2; // Broadcasting operation
}
Linear algebra#
VTensor supports a wide range of mathematical and linear algebra operations, such as sort sum matmul. Please see the API documentation for more details.
#include <lib/vtensor.hpp>
int main() {
auto a = vt::arange(25).reshape(5, 5); // Create a 5x5 tensor
auto b = vt::matmul(a, a); // Matrix multiplication
auto c = vt::sum(b, 0); // Sum along the axis 0
vt::print(c); // Print the tensor
}
Random number generation#
VTensor utilizes CuRand to generate random numbers on the GPU. A global CuRand handeler has been created to reduce the overhead of creating and destroying CuRand handlers. The default is Peudo-random XORWOW generator.
#include <lib/vtensor.hpp>
int main() {
auto a = vt::random::rand(10); // Create a tensor with random values
auto b = vt::random::normal(10); // Create a tensor with random values from a normal distribution
vt::print(b); // Print the tensor
}
Users could create a new CuRand handler, For example, to create a new CuRand handler with the ScrambledSobol32 for quasi-random number generation. The handeler is a unique pointer with CuRandHandleDeleter as the custom deleter.
#include <lib/vtensor.hpp>
int main() {
auto dim = 10;
auto gen = vt::cuda::create_curand_handle<vt::cuda::SCRAMBLED_SOBOL32>(dim); // Create a new CuRand handler
auto a = vt::random::rand(10, *gen.get()); // Create a tensor with qausi-random values
auto b = vt::random::normal(10, 0.0f, 1.0f, *gen.get()); // Create a tensor with qausi-random values from a normal distribution
vt::print(b); // Print the tensor
}