Concepts / Vectorized Implementations

Vectorized Implementations

An element-wise operation applies a rule independently to each tensor entry.

  • Programming

One Rule per Entry

Many tensor operations can be understood by asking whether each output entry depends only on the input entry at the same position. An element-wise operation applies one rule independently to each tensor entry. ReLU follows this pattern: it examines an entry and applies the same ReLU rule to that entry without needing information from neighboring entries.

An element-wise operation applies a rule independently to each tensor entry.

each entrysame positionInput entriesx[0,0], x[0,1], x[1,0],x[1,1]ReLU rulemax(entry, 0)Output entriesone result per position
How can the same ReLU rule be applied independently to many tensor entries at the same time?

ReLU in Two Dimensions

A straightforward implementation makes the independence visible with two loops. The outer loop selects a row, and the inner loop selects each column in that row. At a selected position identified by row index i and column index j, the implementation applies the assignment max(x[i, j], 0). This assignment replaces a negative entry with zero and preserves a nonnegative entry.

outer loopinner loopnext columnnext rowinner loopnext columnfinishedStartRow 0[0,0]first column[1,0]first columnEnd[0,1]next columnRow 1[1,1]next column
What happens next as nested loops visit each row and column of a two-dimensional tensor?

The loops provide an order for visiting entries, but the rule at one position uses only that position's entry. The operation does not need neighboring entries to decide the result at the current position.

Tracing a ReLU Pass

A Two-by-Two ReLU Trace

Apply the loop-based ReLU rule to the generated tensor [[3, -4], [-2, 6]]. Track the value at each position.

Visit [0,0]: The entry is 3. Because it is nonnegative, max(3, 0) preserves it as 3.

Visit [0,1]: The entry is -4. Because it is negative, max(-4, 0) changes it to 0.

Visit [1,0]: The entry is -2. Because it is negative, max(-2, 0) changes it to 0.

Visit [1,1]: The entry is 6. Because it is nonnegative, max(6, 0) preserves it as 6.

The resulting tensor is [[3, 0], [0, 6]].

ReLUReLUReLUReLU[0,0]3[0,0]3[0,1]-4[0,1]0[1,0]-2[1,0]0[1,1]6[1,1]6
Which output position corresponds to each input position when ReLU is applied element by element?

The index map emphasizes two facts. First, each input position has a corresponding output position. Second, ReLU changes only the entries whose values are negative. The positions of the entries do not move; the rule changes their values at those positions.

Why Copy Before Updating

A ReLU implementation copies the input before changing entries so that the updates are made to the copy rather than to the input tensor. The copied tensor becomes the output containing the ReLU results, while the original input remains available in its original form. Without this copy, updating entries would overwrite the input tensor.

From Loops to Parallel Work

Nested loops are a straightforward way to organize the work, but they are not the only organization possible. Since each tensor entry can be processed independently, the entries do not need to wait for neighboring entries to provide information. This makes element-wise operations highly amenable to massively parallel implementations. Implementations organized in this way are also called vectorized implementations, a term associated with vector processor supercomputer architecture.

Loop-based organizationMassively parallel or vectorized organization
Nested loops visit rows and columns explicitly.Independent entries can be processed through a parallel organization.
The processing order is made visible by the outer and inner loops.The same rule can be applied across many independent entries.
Each position is handled by applying the ReLU rule.The independence of positions makes the operation suitable for vectorized implementations.

The opportunity for parallelism comes from independence, not merely from the name ReLU. Any operation whose entry can be processed without information from neighboring entries has the central property needed for this kind of organization.

Debugging by Position

When an element-wise result is incorrect, do not treat the entire tensor as one undifferentiated result. Find the entry where the result first differs from what you expected. The loop identifies that location with row index i and column index j. At that position, compare the old value, the ReLU rule, and the new value. This gives debugging a precise location and a small sequence of facts to inspect.

  • Treating ReLU as if it used neighboring entries.

    The element-wise ReLU rule examines each selected entry independently.

    Fix: Inspect only the value at the current row and column, then apply max(x[i, j], 0).

  • Assuming every entry changes.

    The assignment preserves nonnegative entries and replaces only negative entries with zero.

    Fix: Check the sign of each selected entry before deciding whether its value changes.

  • Updating the input when the intended implementation should preserve it.

    The input is overwritten, so the original tensor is no longer preserved.

    Fix: Copy the input first and apply the updates to the copy.

  • Looking only at the final mismatch without recording its position.

    The loop processes a specific position at a time, so the row and column identify where to compare the old value, rule, and new value.

    Fix: Record the position as [i,j] and inspect that entry's transformation.

Check Your Trace

MEDIUM

For the generated tensor [[3, -4], [-2, 6]], list the positions in the order visited by the nested loops. Then identify which positions change under the ReLU rule and explain why copying the input preserves the original tensor.

Hints
  • The outer loop selects a row, and the inner loop visits the columns in that row.
  • A negative entry is replaced with zero, while a nonnegative entry is preserved.
  • The copied tensor receives the updates.

What do you think happens?

Which positions change when ReLU is applied to the generated tensor [[3, -4], [-2, 6]]?

  • [0,0] and [1,1]
  • [0,1] and [1,0]
  • All four positions
  • No positions
Reveal answer

Answer: [0,1] and [1,0]

The entries at [0,1] and [1,0] are negative, so the ReLU assignment replaces them with zero. The nonnegative entries at [0,0] and [1,1] are preserved.

Key Takeaways

  1. An element-wise operation applies one rule independently to each tensor entry.
  2. Nested loops make the row-and-column processing order explicit for a two-dimensional tensor.
  3. The ReLU assignment max(x[i, j], 0) replaces negative entries with zero and preserves nonnegative entries.
  4. Because entries do not require information from neighboring entries, element-wise work is suitable for massively parallel or vectorized implementations.
  5. Copying before modification preserves the input tensor while producing changed ReLU results in a separate output.

Key Takeaways

  • Element-wise operations apply the same rule independently to individual tensor entries.
  • Nested loops expose how a two-dimensional tensor is visited by row and column.
  • ReLU replaces negative entries with zero and preserves nonnegative entries at their existing positions.
  • Independent entries can be processed through massively parallel or vectorized implementations.
  • Copying before modification preserves the input while updates are written to a separate output.