Skip to content

Tensors

Tensors extend the Value concept to multi-dimensional arrays — enabling batched operations essential for efficient ML.


What is a Tensor?

A tensor is a multi-dimensional array with automatic gradient tracking:

  • Scalar (0D tensor): 42
  • Vector (1D tensor): [1, 2, 3]
  • Matrix (2D tensor): [[1, 2], [3, 4]]
  • 3D tensor: A batch of matrices

Creating Tensors

from neurogebra.core.autograd import Tensor

# From a list
t = Tensor([1.0, 2.0, 3.0])
print(t)        # Tensor(shape=(3,), requires_grad=False)
print(t.data)   # [1. 2. 3.]

# With gradient tracking enabled
t = Tensor([1.0, 2.0, 3.0], requires_grad=True)
print(t)        # Tensor(shape=(3,), requires_grad=True)
print(t.grad)   # [0. 0. 0.] — initialized to zeros

# 2D tensor
m = Tensor([[1.0, 2.0], [3.0, 4.0]], requires_grad=True)
print(m.shape)  # (2, 2)
print(m.ndim)   # 2

Tensor Properties

t = Tensor([1.0, 2.0, 3.0], requires_grad=True)

print(t.shape)          # (3,)
print(t.ndim)           # 1
print(t.data)           # [1. 2. 3.]
print(t.grad)           # [0. 0. 0.]
print(t.requires_grad)  # True

Tensor Operations

Element-wise Arithmetic

a = Tensor([1.0, 2.0, 3.0], requires_grad=True)
b = Tensor([4.0, 5.0, 6.0], requires_grad=True)

c = a + b              # [5.0, 7.0, 9.0]
d = a * b              # [4.0, 10.0, 18.0]
e = a - b              # [-3.0, -3.0, -3.0]
f = a ** 2             # [1.0, 4.0, 9.0]

print(f"a + b = {c.data}")
print(f"a * b = {d.data}")
print(f"a ** 2 = {f.data}")

Scalar Operations

a = Tensor([1.0, 2.0, 3.0], requires_grad=True)

b = a * 3              # [3.0, 6.0, 9.0]
c = a + 10             # [11.0, 12.0, 13.0]

Reduction Operations

a = Tensor([1.0, 2.0, 3.0, 4.0], requires_grad=True)

s = a.sum()     # Sum of all elements → 10.0
m = a.mean()    # Mean of all elements → 2.5

print(f"sum = {s.data}")   # 10.0
print(f"mean = {m.data}")  # 2.5

Backward Pass with Tensors

from neurogebra.core.autograd import Tensor

# Create tensor with gradient tracking
x = Tensor([1.0, 2.0, 3.0], requires_grad=True)

# Computation: y = sum(x²) = 1 + 4 + 9 = 14
y = (x ** 2).sum()

# Backward pass
y.backward()

print(f"x = {x.data}")       # [1. 2. 3.]
print(f"y = x² sum = {y.data}")  # 14.0
print(f"dy/dx = {x.grad}")   # [2. 4. 6.] — which is 2*x

Practical Example: Batch MSE Loss

from neurogebra.core.autograd import Tensor

# Predictions and targets (batch of 4)
predictions = Tensor([2.5, 0.1, 3.0, 7.0], requires_grad=True)
targets = Tensor([3.0, 0.0, 2.5, 8.0])

# MSE = mean((pred - target)²)
diff = predictions - targets
squared = diff ** 2
loss = squared.mean()

print(f"Predictions: {predictions.data}")
print(f"Targets:     {targets.data}")
print(f"MSE Loss:    {loss.data:.4f}")

# Backpropagate
loss.backward()
print(f"Gradients:   {predictions.grad}")
# Each gradient = 2*(pred-target)/n

Zeroing Gradients

Always zero gradients between training iterations:

x = Tensor([1.0, 2.0], requires_grad=True)

# First iteration
y = (x ** 2).sum()
y.backward()
print(f"After 1st backward: grad = {x.grad}")  # [2. 4.]

# Zero and compute again
x.zero_grad()
y = (x ** 2).sum()
y.backward()
print(f"After zero + 2nd backward: grad = {x.grad}")  # [2. 4.] — correct

Key Differences: Value vs Tensor

Feature Value Tensor
Data type Single float NumPy array
Shape Scalar Any shape
Use case Educational, simple networks Batched training
Gradient Single float Array (same shape as data)
Operations +, , *, relu, sigmoid, tanh +, , *, sum, mean

Next: ModelBuilder →