{
  "schemaVersion": 1,
  "slug": "residual-classifier",
  "title": "The residual path",
  "className": "ResidualClassifier",
  "question": "What happens where the skip path rejoins?",
  "description": "Follow a wider representation through a residual block, then see why the classifier head needs the same width.",
  "category": "Skip connections",
  "tags": [
    "Residual",
    "Linear layers",
    "Architecture change"
  ],
  "curator": "TensorViz",
  "attribution": "Original TensorViz teaching example. PyTorch provides the underlying operators.",
  "license": "No separate redistribution license has been declared for these project examples.",
  "limitations": "A small, untrained teaching model, not a ResNet implementation. The public graph is a static architecture snapshot. Recorded validation is a separate asset.",
  "openingStep": "rejoin",
  "provenance": {
    "capturedAt": "2026-09-16T20:05:17.493431+00:00",
    "productRevision": "cf0ab1c9c58c1dc640235b742fa032cade00b43c",
    "python": "3.13.13",
    "torch": "2.7.1",
    "execution": {
      "inputs": {
        "args": [
          {
            "shape": [
              1,
              64
            ],
            "dtype": "float32",
            "fill": "ones"
          }
        ]
      },
      "device": "cpu",
      "mode": "eval",
      "seed": 0,
      "deterministic": true
    },
    "captureMethod": "TensorViz multifile projection API and isolated execution worker",
    "installedJourneyVerified": true,
    "scope": "One explicit CPU forward per version with the recorded input and seed.",
    "installedAfterVerificationUrl": "/examples/installed-after-verification.json",
    "installedJourneyScope": "Separate installed sessions: exact-input A through Codex CLI; native Apply/Discard/Undo/Save; exact-input B through the official MCP SDK. Native footage remains incomplete.",
    "sourceSha256": "51202cd1fd0195075233c3ba6ecc45c6d065e0d3da33a3f87b78d7f39de4b135",
    "outcome": "passed",
    "outputShape": [
      1,
      10
    ]
  },
  "layers": [
    {
      "id": "input",
      "label": "input",
      "op": "Input",
      "kind": "input",
      "parent": null,
      "params": {
        "shape": "1,64"
      }
    },
    {
      "id": "stem",
      "label": "stem",
      "op": "Linear",
      "kind": "layer",
      "parent": null,
      "params": {
        "in_features": 64,
        "out_features": 128
      },
      "source": {
        "line": 24,
        "endLine": 24
      }
    },
    {
      "id": "block",
      "label": "block",
      "op": "Module",
      "kind": "module",
      "parent": null,
      "params": {},
      "source": {
        "line": 25,
        "endLine": 25
      }
    },
    {
      "id": "head",
      "label": "head",
      "op": "Linear",
      "kind": "layer",
      "parent": null,
      "params": {
        "in_features": 128,
        "out_features": 10
      },
      "source": {
        "line": 26,
        "endLine": 26
      }
    },
    {
      "id": "output",
      "label": "output",
      "op": "Output",
      "kind": "output",
      "parent": null,
      "params": {}
    },
    {
      "id": "block.expand",
      "label": "block.expand",
      "op": "Linear",
      "kind": "layer",
      "parent": "block",
      "params": {
        "in_features": 128,
        "out_features": 256
      },
      "source": {
        "line": 8,
        "endLine": 8
      }
    },
    {
      "id": "block.relu",
      "label": "block.relu",
      "op": "ReLU",
      "kind": "layer",
      "parent": "block",
      "params": {},
      "source": {
        "line": 9,
        "endLine": 9
      }
    },
    {
      "id": "block.project",
      "label": "block.project",
      "op": "Linear",
      "kind": "layer",
      "parent": "block",
      "params": {
        "in_features": 256,
        "out_features": 128
      },
      "source": {
        "line": 10,
        "endLine": 10
      }
    },
    {
      "id": "add@block#0",
      "label": "add@block#0",
      "op": "torch.add",
      "kind": "layer",
      "parent": "block",
      "params": {},
      "source": {
        "line": 17,
        "endLine": 17
      }
    }
  ],
  "connections": [
    {
      "id": "edge-1",
      "source": "block.expand",
      "target": "block.relu",
      "sourcePort": null,
      "targetPort": null
    },
    {
      "id": "edge-2",
      "source": "block.relu",
      "target": "block.project",
      "sourcePort": null,
      "targetPort": null
    },
    {
      "id": "edge-3",
      "source": "block.project",
      "target": "add@block#0",
      "sourcePort": null,
      "targetPort": null
    },
    {
      "id": "edge-4",
      "source": "input",
      "target": "stem",
      "sourcePort": null,
      "targetPort": null
    },
    {
      "id": "edge-5",
      "source": "stem",
      "target": "block.expand",
      "sourcePort": null,
      "targetPort": null
    },
    {
      "id": "edge-6",
      "source": "stem",
      "target": "add@block#0",
      "sourcePort": null,
      "targetPort": null
    },
    {
      "id": "edge-7",
      "source": "stem",
      "target": "block",
      "sourcePort": null,
      "targetPort": null
    },
    {
      "id": "edge-8",
      "source": "add@block#0",
      "target": "head",
      "sourcePort": null,
      "targetPort": null
    },
    {
      "id": "edge-9",
      "source": "block",
      "target": "head",
      "sourcePort": null,
      "targetPort": null
    },
    {
      "id": "edge-10",
      "source": "head",
      "target": "output",
      "sourcePort": null,
      "targetPort": null
    }
  ],
  "steps": [
    {
      "id": "wider-features",
      "target": "stem",
      "title": "Give the model more room",
      "note": "The stem projects each input from 64 features to 128. That 128-wide representation enters the residual block."
    },
    {
      "id": "skip-path",
      "target": "block",
      "title": "Follow the path around the layers",
      "note": "Inside the block, the learned path expands 128 features to 256 and projects them back to 128. The original input bypasses those layers so the two paths can be added."
    },
    {
      "id": "rejoin",
      "target": "add@block#0",
      "title": "Meet at the same width",
      "note": "Addition combines the learned path with the untouched residual. Both have 128 features; the skip connection preserves the shape."
    },
    {
      "id": "classifier",
      "target": "head",
      "title": "Match the classifier to its input",
      "note": "The head consumes 128 features and produces 10 outputs. In the earlier version it expected 64; the comparison shows that exact change."
    }
  ],
  "comparison": {
    "beforeGraph": "/examples/residual-before.tensorviz.json",
    "story": "/?scene=compare#demo",
    "note": "Version A expected 64 features at the head. This corrected version accepts the block's 128 features."
  },
  "revision": "13b3cfaa26bbee6f",
  "files": {
    "graph.tensorviz.json": {
      "url": "/models/residual-classifier/13b3cfaa26bbee6f/graph.tensorviz.json",
      "sha256": "3deec033d17920c4a1e99a52307c95e21d8b0456a29638a0f7818cdd2c1db7fc",
      "bytes": 28719
    },
    "model.py": {
      "url": "/models/residual-classifier/13b3cfaa26bbee6f/model.py",
      "sha256": "51202cd1fd0195075233c3ba6ecc45c6d065e0d3da33a3f87b78d7f39de4b135",
      "bytes": 793
    },
    "run.py": {
      "url": "/models/residual-classifier/13b3cfaa26bbee6f/run.py",
      "sha256": "6213701787d5902425c87bf62aae81addae0d3727b1a0c3e4235819f377b2306",
      "bytes": 413
    },
    "requirements.txt": {
      "url": "/models/residual-classifier/13b3cfaa26bbee6f/requirements.txt",
      "sha256": "edb86016b42cb3cc6cdc0c490aab929d3bb098ced4515394f0b55766033e0daf",
      "bytes": 91
    },
    "preview.svg": {
      "url": "/models/residual-classifier/13b3cfaa26bbee6f/preview.svg",
      "sha256": "51bd51cb0360123c2b7e92a76ecaff4f12f5d776396a369a23871d62932a2653",
      "bytes": 2337
    }
  }
}
