32 / 90

Day 32: Topological Sorting, Shared-Node Gradient Accumulation & Gradcheck Tolerances

Master graph traversal and numerical verification: implement post-order DFS topological sorting, preserve multivariate branching with gradient accumulation, and perform central-difference gradchecks with justified tolerances.

Mathematics & Algorithmic Foundations 480 active minutes (8 hours focused study)
01 120 min

Directed Acyclic Graph (DAG) Topological Sorting

Agent-Assisted Engineering Check

Prerequisites

Day 31 computational graph concepts and depth-first search (DFS) fundamentals.

Learning Objective

Understand why reverse-mode backpropagation requires post-order topological sorting so that all outgoing dependencies finish before a node executes its backward closure.

Instructions

Inspect the branching shared-node graph structure using the CLI:

python3 projects/autograd/cli.py graph --preset shared-node --format ascii

Notice that node a feeds into both sum $(a+b)$ and final product $(a+b) \cdot a$. A simple BFS or arbitrary traversal would run a._backward() before all downstream gradient contributions have arrived.

Practice & Prediction Log

Consider the expression $f = (a + b) \cdot a$, where $a = 3.0, b = 4.0$.
1. Trace the depth-first search (DFS) traversal starting at root node $f$.
2. List the post-order sequence of nodes visited.
3. Verify that the reversed sequence orders $f$ first, then the sum node, and finally leaf nodes $a, b$.

Independent Mastery Criterion

The learner independently writes a DFS post-order topological sort algorithm without relying on third-party graph libraries.

Authoritative Source Resources & Provenance

linking MIT

micrograd: A tiny scalar-valued autograd engine

Author: Andrej Karpathy | Original Source Link ↗

Relevant Section / Range: micrograd/engine.py: class Value (_backward closures and backward() topological sort); README 'Example usage'

Verified Version & Date: commit a9a9f94 (Verified: 2026-10-30)

Selection Rationale:

Clear reference implementation of recursive DFS topological sort for reverse-mode ordering.

Source Prerequisites:

Graph traversal fundamentals (DFS/BFS)

Safe Fallback (Offline Resilience):

Local implementation in projects/autograd/engine.py.

Compared Candidate Sources & Selection Analysis (2)
PyTorch autograd C++ engine ↗ compared_alternative [Modified BSD]

Production scale, but too large and complex for tracing by hand in introductory lessons.

Autograd (HIPS) ↗ compared_alternative [MIT]

Vectorized autograd; micrograd's pure scalar model is pedagogical for hand backprop.

02 120 min

Shared-Node Gradient Accumulation and Multivariable Chain Rule

Independent Mastery Check

Prerequisites

Multivariable calculus chain rule (sum over all paths) and Activity 32-01.

Learning Objective

Prove that variables with multiple consumer branches require accumulation (`+=`), and demonstrate how assignment (`=`) creates subtle gradient corruption.

Instructions

Execute the forward-backward pass on the shared-node graph preset:

python3 projects/autograd/cli.py forward-backward --preset shared-node

Observe that for $f = (a + b) \cdot a$ at $a = 3.0, b = 4.0$:
$\frac{\partial f}{\partial a} = 2a + b = 2(3) + 4 = 10.0$.
Verify that the backward pass correctly accumulates both paths.

Practice & Prediction Log

Given $f(a, b) = (a + b) \cdot a$ with $a = 3.0, b = 4.0$:
1. Let $u = a + b$. Then $f = u \cdot a$. Calculate $\frac{\partial f}{\partial u}$ and $\frac{\partial f}{\partial a}$ from the multiplication step.
2. From the addition step $u = a + b$, calculate $\frac{\partial u}{\partial a}$ and its contribution to $a$.
3. Show how applying $\frac{\partial f}{\partial a} = \frac{\partial f}{\partial u} \frac{\partial u}{\partial a} + \left(\frac{\partial f}{\partial a}\right)_{\text{direct}}$ yields $10.0$.
4. Explain what happens if an implementer writes self.grad = ... instead of self.grad += ....

Independent Mastery Criterion

The learner proves why `+=` is mathematically required for multi-path DAG nodes and demonstrates the numerical defect caused by assignment.

Authoritative Source Resources & Provenance

linking SIAM Copyright / Academic Linking Only No text extraction or distribution permitted

Evaluating Derivatives: Principles and Techniques of Algorithmic Differentiation

Author: Andreas Griewank, Andrea Walther | Original Source Link ↗

Relevant Section / Range: Section 3.2: Accumulation along Adjoint Graphs

Verified Version & Date: 2nd Edition, SIAM 2008 (Verified: 2026-10-30)

Selection Rationale:

Mathematical proof showing that total derivative equals the sum of adjoint contributions across all outbound paths.

Source Prerequisites:

Multivariate calculus

Safe Fallback (Offline Resilience):

Self-contained mathematical derivations in activity text.

Compared Candidate Sources & Selection Analysis (2)
micrograd: A tiny scalar-valued autograd engine ↗ compared_alternative [MIT License]

Executable scalar reference implementation the learner later rebuilds; the textbook supplies the formal reverse-mode theory.

Broad survey taxonomy of the field; the textbook was selected for its rigorous treatment of reverse-mode complexity.

03 120 min

Finite-Difference Numerical Gradient Checking (Gradcheck) & Tolerances

Agent-Assisted Engineering Check

Prerequisites

Taylor series expansion and floating-point error awareness (IEEE 754).

Learning Objective

Implement two-sided central difference numerical gradient checking, establish rigorous relative/absolute tolerance thresholds, and understand non-differentiable kink points.

Instructions

Run the numerical gradient check on a complex multi-operator expression:

python3 projects/autograd/cli.py gradcheck --preset complex

Then run the gradcheck on the ReLU kink point:

python3 projects/autograd/cli.py gradcheck --preset relu-kink

Inspect the relative error and the kink disclosure in the output.

Practice & Prediction Log

1. Explain why central difference $\frac{f(x+h) - f(x-h)}{2h}$ has truncation error $\mathcal{O}(h^2)$ whereas forward difference $\frac{f(x+h) - f(x)}{h}$ has error $\mathcal{O}(h)$.
2. Why can we not make $h$ arbitrarily small (e.g. $10^{-20}$)?
3. Calculate the relative error between analytical gradient $g_a = 10.0$ and numerical gradient $g_n = 9.999999999$ and verify it meets $\text{rtol} = 10^{-3}$.

Independent Mastery Criterion

The learner justifies selection of step size $h=10^{-5}$ and tolerances $\text{rtol}=10^{-3}, \text{atol}=10^{-5}$, and explains why kinks like $\text{ReLU}(0)$ produce expected mathematical divergence.

Authoritative Source Resources & Provenance

linking BSD-style License

PyTorch Autograd: Numerical Gradient Checking (torch.autograd.gradcheck)

Author: PyTorch Core Team | Original Source Link ↗

Relevant Section / Range: Finite-difference formula, default tolerances (rtol, atol), and step-size selection

Verified Version & Date: PyTorch 2.5 (Verified: 2026-10-30)

Selection Rationale:

Widely adopted benchmark for validating analytical autodiff against central difference approximations.

Source Prerequisites:

Numerical methods basics and IEEE 754 floating-point awareness

Safe Fallback (Offline Resilience):

Local gradcheck implementation in projects/autograd/gradcheck.py.

Compared Candidate Sources & Selection Analysis (2)
JAX documentation: Automatic differentiation ↗ compared_alternative [Apache-2.0]

Alternative framework autodiff API; PyTorch gradcheck was selected to match the projects/autograd numerical checks used in the drill.

numdifftools: automatic numerical differentiation ↗ compared_alternative [BSD-3-Clause]

General finite-difference toolkit; PyTorch gradcheck was selected because it integrates directly with the tensor autograd objects the drill verifies.

04 120 min

Independent Mastery Check: Topological Order & Numerical Verification

Independent Mastery Check

Prerequisites

Activities 32-01 through 32-03.

Learning Objective

Verify independent mastery of DAG topological ordering, gradient accumulation mechanics, and numerical gradcheck tolerances without AI assistance.

Instructions

Complete the diagnostic check below under declared AI-free conditions. Record your answers and explanations in the draft area.

Practice & Prediction Log

Consider a computation graph where input $x = 2.0$ branches into $y_1 = x^2$ and $y_2 = 3x$, and loss is $L = y_1 + y_2$.
1. Determine the analytical derivative $\frac{\partial L}{\partial x}$.
2. Compute the central finite difference approximation at $x = 2.0$ with $h = 0.001$.
3. Compute the relative error between analytical and numerical gradients.

Objective Knowledge Check: Topology, Accumulation & Numerical Gradcheck

Answer the following diagnostic questions to verify your understanding. Select your declared assistance condition before submitting.

Declared Assistance Condition

Note: AI-free work is an honest declared condition, not claimed surveillance.

1.

In a computational graph where node A feeds into both node B and node C, and both B and C feed into loss L, in what order must their backward passes execute?

2.

If node a is referenced twice in an expression, contributing $+3.0$ from branch 1 and $+7.0$ from branch 2, what bug occurs if the implementation writes self.grad = ... instead of self.grad += ...?

3.

When performing numerical gradient checking on $\text{ReLU}(x)$ at exactly $x = 0.0$ with $h = 10^{-5}$, why does the central difference return $0.5$ while analytical autodiff returns $0.0$?

Attempt History & Evidence

    Independent Mastery Criterion

    Independent derivation of multi-path gradient $\frac{\partial L}{\partial x} = 7.0$ and calculation of finite difference verification matching analytical gradient within $10^{-5}$.

    Authoritative Source Resources & Provenance

    linking Modified BSD

    PyTorch Documentation: Autograd Mechanics

    Author: PyTorch Contributors | Original Source Link ↗

    Relevant Section / Range: How autograd encodes the history

    Verified Version & Date: PyTorch 2.5 Documentation (Verified: 2026-10-30)

    Selection Rationale:

    Official reference for computational graph construction, backward pass execution, and in-place mutation pitfalls.

    Source Prerequisites:

    Basic understanding of computational graphs and tensors.

    Safe Fallback (Offline Resilience):

    The training loop mechanics and zero_grad requirements are illustrated with runnable Python code.

    Compared Candidate Sources & Selection Analysis (2)
    TensorFlow tf.GradientTape Documentation ↗ compared_alternative [Apache 2.0]

    Alternative tape-based execution; PyTorch dynamic graph semantics are standard in modern LLM research.

    JAX autodiff cookbook ↗ compared_alternative [Apache 2.0]

    Functional transformations (grad, vjp); PyTorch object-based graph is closer to the beginner micrograd model.

    linking BSD-3-Clause

    SciPy numerical derivative reference

    Author: SciPy Developers | Original Source Link ↗

    Relevant Section / Range: derivative API: finite differences, step-size iteration, tolerances

    Verified Version & Date: SciPy documentation, verified 2026-10-30

    Selection Rationale:

    Documents numerical differentiation as an approximation with finite step sizes and stopping criteria.

    Source Prerequisites:

    Python arithmetic and the definition of a derivative

    Safe Fallback (Offline Resilience):

    The local Day 18 tables and pure-Python snippets reproduce the relevant finite-difference behavior without SciPy.

    Compared Candidate Sources & Selection Analysis (2)
    NumPy: numpy.gradient ↗ compared_alternative [BSD 3-Clause License]

    Array-oriented gradient estimation on sampled grids; the SciPy derivative reference matches the pointwise finite-difference helper the exercises implement.

    SymPy Calculus tutorial ↗ compared_alternative [BSD License]

    Symbolic rather than numerical differentiation; useful for exact cross-checks but not the finite-difference practice target.