advanced26 min studyLesson 509 in Engineering

Repeated sparse indices accumulate before nonlinear updates

Derive a gather's scatter-add adjoint, distinguish duplicate storage entries from gradient identity, and budget sparse values and indices under supported runtime layouts.

On this page

What you’ll understand

  • Accumulate repeated gather-index cotangents into the correct parameter rows.
  • Explain uncoalesced COO duplicates and why nonlinear operations need semantic care.
  • Compare sparse and dense payload including index overhead and runtime support.

An embedding lookup can touch only a few rows of a large table, so its input gradient has useful structure. The same row may be selected several times, and reverse mode must add every occurrence's contribution. A sparse storage format can represent those contributions separately before combining them. Distinguish the mathematical gradient from its physical entries before interpreting a duplicate index as a duplicate parameter or applying a nonlinear optimizer update to each fragment.

The adjoint of gathering is accumulation

For a table E with one row per identifier, a gather output y_j takes row E at index i_j. A reverse cotangent for each occurrence contributes to that same table row. If the row appears twice, both vectors add. Rows never selected receive zero under this simple gather-only model. This is a sparse linear map with respect to the table values at fixed indices, but the integer indices are not ordinary differentiable coordinates. A program that wants gradients for selecting an index needs a different explicitly defined relaxation or estimator.

A naive reverse implementation that assigns rather than adds can lose earlier occurrences. Parallel scatter-add implementations must also respect accumulation semantics, even though floating-point summation order can affect final rounding. PyTorch 2.9 documents operation-specific shape and backward restrictions and possible device nondeterminism for scatter operations. Those implementation details are separate from the exact real-valued adjoint. Test repeated indices and nontrivial vector cotangents; a dataset with unique indices can conceal a fundamentally wrong gather derivative.

yj=Eij,:,Eˉi,:=∑j:ij=iyˉjy_j=E_{i_j,:},\qquad \bar E_{i,:}=\sum_{j:i_j=i}\bar y_j
E is a real dimensionless table, i_j fixed integer row indices, and each cotangent row has the table's feature width. The sum defines the exact gather adjoint; it does not differentiate the indices or guarantee a particular floating-point accumulation order.↔ Scroll wide equations horizontally.

Storage duplicates can represent one summed gradient

PyTorch 2.9's sparse COO documentation permits uncoalesced duplicate coordinates whose values contribute by addition. Coalescing combines duplicates and orders the representation under its contract. The mathematical tensor is the sum at each coordinate, not whichever duplicate appears last. A nonlinear operation on separate fragments can differ from the operation on their sum: squaring values one and two separately gives a represented total five, while squaring the combined value three gives nine. An optimizer or custom kernel must honor the layout's semantics instead of assuming every stored coordinate is unique.

Sparse gradient support depends on the operation, layout, device, and optimizer. Embedding can request sparse gradients under its documented options, but not every optimizer accepts that representation or implements every combination. Do not infer support from the fact that a sparse tensor can be constructed. A zero stored value can also remain structurally present after cancellation; numerical zero and absent storage are different concepts. Verify supported transformations, coalescing requirements, accumulation, and optimizer state rather than declaring that sparse automatically means less memory or fewer arithmetic operations.

Bsparse,payload≈k(dbv+bi),Bdense,payload=NdbvB_{\rm sparse,payload}\approx k(db_v+b_i),\qquad B_{\rm dense,payload}=Ndb_v
For a row-sparse example, k stored rows each have d values of b_v bytes plus one row index of b_i bytes; a dense N-row table has Nd values. Duplicates, metadata, layout-specific indices, optimizer state, and workspaces can change actual cost.↔ Scroll wide equations horizontally.

Verify structure and numerical behavior together

Compare a sparse derivative with a small dense reference after converting both to the same mathematical layout. Include repeated indices, canceled contributions, unused rows, different feature widths, and several accumulation steps. Measure index traffic and coalescing work alongside value payload, especially when the selected set is not very sparse. A representation that saves gradient storage can still require dense parameter or optimizer state. Keep the promised memory category explicit and test whether batching changes duplicate frequency or backend behavior.

The vector lab illustrates componentwise addition on paper rather than sparse storage. Reset, explicitly set BOTH angle 0 degrees and magnitude one, inspect vector (1,0), then Play or Step. Reset and re-set BOTH angle 90 degrees and magnitude two for vector (0,2). Their paper sum is (1,2), not either last assignment. Edits retain t; playback traces one selected vector and never stores both, scatters rows, or coalesces duplicates. Use the example only to inspect accumulation components; the worked gather trace determines the real indexed gradient.

Two occurrences of one embedding row must add

Let E have rows (0,1), (2,3), and (4,5). Gather indices (1,1,2), with output cotangents (1,2), (3,−1), and (−2,4). Indices are zero-based and fixed.

  1. The first two occurrences both refer to row one, so add their cotangents: (1,2)+(3,−1)=(4,1). Overwriting with the second would lose the first contribution.

  2. Row two receives (−2,4), and unused row zero receives (0,0). The full table gradient is therefore rows (0,0),(4,1),(−2,4).

  3. As a scalar check, the weighted gathered output is (2,3)·(1,2)+(2,3)·(3,−1)+(4,5)·(−2,4)=8+3+12=23. Its table derivative has the accumulated rows above.

The result

Repeated indices represent repeated uses of the same parameter row, requiring addition rather than assignment or separate nonlinear updates.

Explore the model

Interactive lab

Interactive lab · vectors

Accumulation adds components, not the last writer

For EACH run Reset, set BOTH angle and magnitude, inspect, then Play or Step. Compare (0°,1), vector (1,0), with (90°,2), vector (0,2), and add them on paper. Edits retain t. This instrument displays one vector at a time and implements no sparse table, scatter, duplicate storage, or coalescing.

Accumulation adds components, not the last writerPlayback traces a fixed vector and its projections. Angle and magnitude set the geometry; the moving marker does not change them. Current readings: x component: 1.393; y component: 0.975; Magnitude: 1.7. All parameters are adjustable with the labeled controls below.−7.46−3.7303.737.46−3.5−1.7501.753.5xyvvₓ = 1.39
Vectorx / y projectionsTrace marker
x component
1.393
y component
0.975
Magnitude
1.7
t = 0 s

Playback traces a fixed vector and its projections. Angle and magnitude set the geometry; the moving marker does not change them. Parameter changes pause playback and recompute the model at the current elapsed time. Reset restores both parameters and returns time to zero. Playback starts paused. Adjust either parameter, then choose Play or Step.

Look forRepeated derivative contributions add in the same coordinates; an indexed runtime must preserve that semantics independently of storage format.

Check your understanding

Why can squaring uncoalesced duplicate values independently differ from squaring the represented summed coordinate?

Try it yourself

A row-sparse gradient touches three unique rows of a 1,000×8 table. Values use four bytes and one row index uses eight bytes. Compare ideal sparse payload with dense gradient payload, excluding all overhead and optimizer state.

Take a moment to make a prediction or work it out on paper. Open a hint when you need one.

Give me a hint

Count eight values plus one index per stored row, not just the nonzero values.

Compare with the solution

Sparse payload is 3×(8×4+8)=120 bytes. Dense gradient payload is 1,000×8×4=32,000 bytes. This comparison concerns gradient payload only; duplicate entries, metadata, parameter storage, optimizer state, and operation support remain separate costs.

Take it with you

  • A gather's reverse rule accumulates every occurrence into its indexed row.
  • Uncoalesced duplicate storage denotes a summed tensor, not separate parameters.
  • Sparse savings depend on indices, layouts, optimizer support, and the measured memory category.

Read further

Original sources and deeper explanations to follow at your own pace.

Optional progress, saved in this browser when available. Revisit any lesson at any time.

Lesson not marked complete.