Tensor¶
Tensor is NTK's base data object for multi-dimensional array storage, data operations, and
automatic gradient calculation and differiation.
All functions and objects in NTK expect and return Tensor data
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
data
|
numpy array or list
|
Tensor data (lists are converted to numpy arrays) |
required |
requires_grad
|
bool
|
Whether the tensor tracks gradients (defaults to False) |
False
|
Data¶
Tensors hold multi-dimensional arrays of numeric data only. If the data passed to Tensor isn't a NumPy array, it will try to convert it to one and throw an error if not possible. The data types accepted are NumPy arrays, python lists and tuples, and numerics.
Note that no matter the datatype passed Tensor will always store it as a NumPy array.
import neuraltoolkit as ntk
import numpy as np
a = ntk.Tensor(np.array([1, 2, 3, 4, 5]))
# array([1, 2, 3, 4, 5])
b = ntk.Tensor([0.1, 0.2, 0.3, 0.4, 0.5])
# array([0.1, 0.2, 0.3, 0.4, 0.5])
c = ntk.Tensor((0, 0, 0, 0, 0))
# array([0, 0, 0, 0, 0])
d = ntk.Tensor(10)
# array([10])
Accessing Tensor Data¶
Tensor data can be accessed via Tensor.data
To display tensor data to the terminal simply use print():
a = ntk.Tensor([1, 2, 3, 4, 5])
print(a)
Terminal Output
Tensor:
[1. 2. 3. 4. 5.]
Gradients¶
Tensors can hold gradients. Gradients are the values that are updated during backpropagation and are used to update the parameters of a model. To create a tensor with gradients set the requires_grad argument to True upon instantiation. If not defined then it will default to False
ntk.Tensor([1, 2, 3], requires_grad=True)
When defining a tensor as the parameters to a model, use Parameter A subclass of Tensor that always uses gradients
To access a tensor's gradient use tensor.grad
Tensor gradients can be cleared using .clear_grad(). If training a model without Trainer, the gradients must be cleared after each optimization step.
Operations¶
Beyond holding data, Tensors can perform math on their data and provide functionality for slicing and indexing similar to arrays and lists.
Math¶
Tensors accept most mathematical operators with functionality for tensor to tensor and tensor to scalar math.
All tensor math operaitons are not in-place and return a new tensor
| Operation | Expression | Result |
|---|---|---|
| Addition | a + b |
Element-wise addition |
| Subtraction | a - b |
Element-wise subtraction |
| Multiplication | a * b |
Element-wise multiplication |
| Division | a / b |
Element-wise division |
| Matrix multiplication | a @ b |
Matrix multiplication |
| Power | a ** 2 |
Element-wise exponentiation |
| Negation | -a |
Element-wise negation |
x = ntk.Tensor([1, 2, 3])
y = ntk.Tensor([4, 5, 6])
z = (x + y) * 2
# z -> Tensor: [10, 14, 18]
Indexing¶
Tensors can be indexed, sliced, and interated over similar to numpy arrays.
| Method | Syntax |
|---|---|
| Indexing | tensor[a] |
| Slicing | tensor[a:b:c] |
| Iteration | for item in tensor: |
Autograd¶
Tensors have a built-in autograd (automatic gradient differentiation) engine making backpropagation simple.
Whenever an operation is applied to a tensor, whether it be indexing or math, a gradient chain graph is built. Simply calling backward() on the final tensor (usually loss) will automatically update the gradients of all tensors in the chain, after which optimizers can be used to update parameters.
a = ntk.Tensor([1, 2], requires_grad=True)
b = ntk.Tensor([3, 4], requires_grad=True)
c = a * b
z = c - 3
z.backward()
print(a.grad) # [3, 4]
print(b.grad) # [1, 2]