Math for AI course · Lesson 5 of 180

Tensor Indices for AI: Reading Samples, Tokens, and Features

Learn to read tensor subscripts, translate batch-token-feature addresses into NumPy, and catch valid-looking axis mistakes in AI code.

Share this article

An AI program reads X[1, 2, 0] and returns 0.8. A nearby expression, X[1, 0, 2], returns 0.3. Both addresses are valid. Only one means “the first feature of the last token in the second example.”

The difference is an index: a position used to locate a value inside an ordered structure. Indices are small pieces of notation, but they determine which example, token, feature, pixel, or model output a calculation actually uses. A wrong index can therefore produce a believable number instead of a helpful error.

By the end of this lesson, you will be able to read indexed samples and coordinates, follow a batch-token-feature tensor address, translate a mathematical subscript into NumPy, and detect an address whose numbers are legal but whose axis meanings are wrong. This adds order to the dataset collections from Lesson 4. The official Mathematics for Machine Learning companion places this notation on the route from numerical data to the vectors, matrices, and models used later in the course.

An index answers “which position?”

Suppose an ordered dataset contains three examples:

D=(x1,x2,x3).D=(x_1,x_2,x_3).

The subscript in x2x_2 says “select the example at position 2.” It does not say that the example’s value is 2. If the second example is the pair x2=(1.7,0.4)x_2=(1.7,-0.4), then x2x_2 names the whole pair.

Add a second subscript to select a coordinate inside that example:

x2,1=1.7andx2,2=0.4.x_{2,1}=1.7 \qquad\text{and}\qquad x_{2,2}=-0.4.

Read x2,1x_{2,1} from left to right: choose example 2, then coordinate 1. The indices form an address; the number stored at that address is the value.

This also separates position from identity. Moving a sample from position 2 to position 7 changes its index even if its stable ID, image pixels, and label do not change. Indices are useful addresses, not permanent names for real-world objects.

Each subscript chooses one axis

An axis is one direction in which an array is organized. A table has a row axis and a column axis. Here, a tensor is a multidimensional array: it can have those two axes or add more axes for concepts such as batches and tokens.

Consider an activation tensor

XRB×T×F,X\in\mathbb{R}^{B\times T\times F},

where:

  • BB is the number of examples in the batch;
  • TT is the number of token positions per example; and
  • FF is the number of features stored for each token.

The notation RB×T×F\mathbb{R}^{B\times T\times F} says that every entry is a real number and that the tensor has shape B×T×FB\times T\times F. One scalar entry is

Xb,t,f,X_{b,t,f},

which means: choose batch position bb, token position tt, and feature position ff, in that order.

For a tensor with shape 2×3×42\times3\times4, a one-based mathematical convention allows

1b2,1t3,1f4.1\le b\le2, \qquad 1\le t\le3, \qquad 1\le f\le4.

The shape supplies the range of each index. The axis names supply the meaning. Neither fact replaces the other.

One address, worked all the way to a value

Use the following two-batch tensor. Each batch item contains three token rows, and every token has four feature values.

Follow the address X2,3,1: choose batch item 2, then token 3, then feature 1. The selected cell contains 0.8.
Batch item 1 tensor grid Three token rows and four feature columns for batch item 1.Batch item 1feature index →token index →f1f2f3f4token 10.20.8-0.10.4token 21.1-0.30.50.0token 30.70.60.2-0.4 Batch item 2 tensor grid Three token rows and four feature columns for batch item 2. Token 3, feature 1 is selected and has value 0.8.Batch item 2feature index →token index →f1f2f3f4token 1-0.20.90.30.1token 20.4-0.71.20.5token 30.8 ★0.1-0.61.5★ X₂,₃,₁ = 0.8
Batch item 1: token rows by feature columns
TokenFeature 1Feature 2Feature 3Feature 4
10.20.8-0.10.4
21.1-0.30.50.0
30.70.60.2-0.4
Batch item 2: token rows by feature columns
TokenFeature 1Feature 2Feature 3Feature 4
1-0.20.90.30.1
20.4-0.71.20.5
30.80.1-0.61.5

This stepwise reading matters more than memorizing a letter order. Another project might store tokens before batches or use height, width, and channel axes for images. The code and documentation must state the contract.

NumPy starts at zero

Many mathematics texts label positions beginning at 1. Python and NumPy use zero-based indexing, so the first position is 0. NumPy’s official indexing guide also confirms that one integer per dimension selects one element and that the valid nonnegative index for an axis of size dd satisfies 0i<d0\le i<d.

Intended positionOne-based mathZero-based NumPy
Batch item 2b=2b=2b = 1
Token 3t=3t=3t = 2
Feature 1f=1f=1f = 0
Complete addressX2,3,1X_{2,3,1}X[1, 2, 0]

Here is the complete tensor and several verified selections:

import numpy as np

X = np.array([
    [[ 0.2,  0.8, -0.1,  0.4],
     [ 1.1, -0.3,  0.5,  0.0],
     [ 0.7,  0.6,  0.2, -0.4]],
    [[-0.2,  0.9,  0.3,  0.1],
     [ 0.4, -0.7,  1.2,  0.5],
     [ 0.8,  0.1, -0.6,  1.5]],
])

print("shape:", X.shape)
print("one activation:", X[1, 2, 0])
print("last token of example 2:", X[1, 2])
print("feature 1 of every last token:", X[:, 2, 0])
shape: (2, 3, 4)
one activation: 0.8
last token of example 2: [ 0.8  0.1 -0.6  1.5]
feature 1 of every last token: [0.7 0.8]

The colon in X[:, 2, 0] means “keep every position on this axis.” The first axis remains, while token and feature receive specific indices, so the result contains one value for each of the two batch items.

The shape attribute reports (2, 3, 4), but the tuple itself does not say “batch, token, feature.” Those names come from the program’s data contract.

Return to the opening expressions:

X[1, 2, 0]  # 0.8: batch 2, token 3, feature 1
X[1, 0, 2]  # 0.3: batch 2, token 1, feature 3

Both addresses fit the shape. NumPy cannot know that the second line swapped the token and feature meanings. This is a semantic indexing bug: the program retrieves a real entry, but not the entry the calculation intended.

Useful defenses include naming the axis contract beside the tensor, checking the shape at boundaries, and assigning index variables descriptive names:

batch_index = 1
token_index = 2
feature_index = 0

activation = X[batch_index, token_index, feature_index]
assert X.shape == (2, 3, 4)
assert activation == 0.8

The assertion checks this example. The descriptive variables preserve the reasoning that led to the address.

Bounds errors are safer than silent axis errors

For the zero-based shape (2, 3, 4), the last nonnegative address is X[1, 2, 3]. X[2, 0, 0] is invalid because batch index 2 would request a third item from an axis containing only two items. NumPy raises IndexError rather than returning a made-up value.

Negative indices are a Python convention: -1 selects the final position of an axis, so X[-1, -1, -1] is another way to read X[1, 2, 3]. That shorthand is valid code, but it should not be silently translated into a one-based mathematical subscript. State the convention whenever the distinction matters.

The next lesson will use these addresses inside sums. Once xix_i clearly means the iith example and i\ell_i means its loss, a symbol such as ii\sum_i\ell_i becomes a compact instruction to visit every indexed loss and combine the values.

Check your understanding

Question 1

If x₄ = (2.5, −1.0, 0.3), what do x₄ and x₄,₂ refer to?

Show the step-by-step solution

First read the number of subscripts.

  1. x4x_4 has one index, so it selects the whole example at position 4.
  2. The given example is the three-coordinate value (2.5,1.0,0.3)(2.5,-1.0,0.3).
  3. x4,2x_{4,2} adds a coordinate index, so it selects coordinate 2 inside that example.

Therefore,

x4=(2.5,1.0,0.3)andx4,2=1.0.x_4=(2.5,-1.0,0.3) \qquad\text{and}\qquad x_{4,2}=-1.0.

The subscript 4 is an address; it is not the stored value.

Question 2

Use the visual to calculate X₂,₂,₃. Show each axis choice.

Show the step-by-step solution

Follow the indices in their declared batch-token-feature order.

  1. b=2b=2 chooses batch item 2.
  2. t=2t=2 chooses its second token row: (0.4,0.7,1.2,0.5)(0.4,-0.7,1.2,0.5).
  3. f=3f=3 chooses the third coordinate of that row.

Thus,

X2,2,3=1.2.X_{2,2,3}=1.2.

Choosing feature 3 before token 2 would change the question because the axes are ordered.

Question 3

Translate the one-based mathematical address X₂,₃,₄ into zero-based NumPy and find its value.

Show the step-by-step solution

Subtract 1 from each position when moving from the stated one-based convention to NumPy:

(2,3,4)(1,2,3).(2,3,4)\longrightarrow(1,2,3).

The code address is therefore X[1, 2, 3]. In batch item 2, token 3 is (0.8,0.1,0.6,1.5)(0.8,0.1,-0.6,1.5), and feature 4 is 1.51.5. Hence

X2,3,4=1.5.X_{2,3,4}=1.5.

Question 4

For a zero-based tensor with shape (2, 3, 4), classify X[0, 2, 3], X[1, 3, 0], and X[2, 0, 0] as in bounds or out of bounds.

Show the step-by-step solution

Translate the shape into the valid nonnegative ranges:

b{0,1},t{0,1,2},f{0,1,2,3}.b\in\{0,1\},\qquad t\in\{0,1,2\},\qquad f\in\{0,1,2,3\}.
  • X[0, 2, 3] is in bounds because every index belongs to its range.
  • X[1, 3, 0] is out of bounds because token index 3 is not in {0,1,2}\{0,1,2\}.
  • X[2, 0, 0] is out of bounds because batch index 2 is not in {0,1}\{0,1\}.

The first failing axis is enough for NumPy to reject the complete address.

Question 5

A developer intends batch 2, token 3, feature 1 but writes X[1, 0, 2]. Why does no bounds error occur, and how should the line be repaired?

Show the step-by-step solution

For shape (2, 3, 4), the indices (1, 0, 2) are mechanically valid:

1<2,0<3,2<4.1<2,\qquad 0<3,\qquad 2<4.

NumPy therefore returns the value at batch 2, token 1, feature 3, which is 0.30.3. The library cannot infer the intended axis meanings.

Convert the intended one-based positions (2,3,1)(2,3,1) to zero-based positions $(1,2,0)`. The repaired line is:

activation = X[1, 2, 0]  # 0.8

This is a semantic bug rather than a bounds bug, so descriptive variable names and an explicit axis contract are useful defenses.

Question 6

What does X[-1, -1, -1] select, and why is −1 not a permanent identity for that value?

Show the step-by-step solution

In NumPy, -1 means “the last position on this axis.” For shape (2, 3, 4), the last zero-based positions are (1, 2, 3). Therefore,

X[1,1,1]=X[1,2,3]=1.5.X[-1,-1,-1]=X[1,2,3]=1.5.

The meaning depends on the current shape and ordering. If another batch item or token were appended, -1 would point somewhere else. It is a relative address, not a stable ID attached to the stored value.

Sources

  1. Mathematics for Machine Learning companion website
  2. Mathematics for Machine Learning book PDF
  3. NumPy documentation: indexing on ndarrays
  4. NumPy documentation: ndarray shape