{
  "nbformat": 4,
  "nbformat_minor": 5,
  "metadata": {
    "kernelspec": {
      "name": "aner",
      "display_name": "Aner",
      "language": "aner"
    },
    "language_info": {
      "name": "aner",
      "file_extension": ".aner"
    },
    "aner": {
      "execution_mode": "persistent-session",
      "runtime_mode": "development"
    }
  },
  "cells": [
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": "# Neural research with explicit placement\n\nIris: Fisher (1936), UCI, CC BY 4.0. Split before fitting normalization. Sequential keeps layers visible; use the custom class source example for your own forward and loss.\n\nInspect variables, CPU placement, loss, gradients, and measured timing after completed cells. Progress text appears after each cell returns; notebook streaming is planned. In VS Code choose Inspector and Open Development Training Report. The supported notebook extension is `.anernb`.\n",
      "id": "nresearch-0"
    },
    {
      "cell_type": "code",
      "metadata": {},
      "source": [
        "import aner.dataset\n",
        "import aner.nn\n",
        "import aner.ml\n",
        "import aner.dev\n",
        "print(nn.devices())\n",
        "let split = dataset.iris().split(test: 0.2, seed: 2026)\n",
        "let network = nn.sequential(seed: 42)\n",
        "    .dense(inputs: 4, outputs: 16, initialization: \"he\").relu()\n",
        "    .dense(inputs: 16, outputs: 3, initialization: \"xavier\")\n",
        "let plan = ml.classifier(network, standardize: true, optimizer: \"adam\").on(device: \"cpu\")\n",
        "print(plan.summary())"
      ],
      "execution_count": null,
      "outputs": [],
      "id": "nresearch-1"
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": "## Partial training\n\nThe epoch horizon is fixed. ETA is measured after warmup and is approximate; it is never an estimate of convergence.\n",
      "id": "nresearch-2"
    },
    {
      "cell_type": "code",
      "metadata": {},
      "source": [
        "let partial = plan.fit(split.train(), epochs: 200, rate: 0.02, progress: true)\n",
        "print(partial.training_loss())\n",
        "print(partial.training_seconds())"
      ],
      "execution_count": null,
      "outputs": [],
      "id": "nresearch-3"
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": "## Inspect real values\n\nPredictions and inspected weights are detached CPU tensors.\n",
      "id": "nresearch-4"
    },
    {
      "cell_type": "code",
      "metadata": {},
      "source": [
        "let learned = partial.weights(layer: 0)\n",
        "dev.capture(\"First layer\", learned)\n",
        "print(learned.device())\n",
        "print(partial.evaluate(split.test()).summary())"
      ],
      "execution_count": null,
      "outputs": [],
      "id": "nresearch-5"
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": "## Continue from the immutable fitted model\n\nAdam moments, update count, and fitted normalization are reused. A production run uses the same updates and backend.\n",
      "id": "nresearch-6"
    },
    {
      "cell_type": "code",
      "metadata": {},
      "source": [
        "let final = plan.warm_start(partial).fit(split.train(), epochs: 200, rate: 0.02)\n",
        "print(final.evaluate(split.test()).summary())\n",
        "print(final.summary())"
      ],
      "execution_count": null,
      "outputs": [],
      "id": "nresearch-7"
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": "## Production\n\nChoose Prod in VS Code and rerun all cells, or use `%aner prod` in Jupyter. Optional progress is independent of development recording. Checkpoint save and load are demonstrated in the complete `neural_adam_resume.aner` download.\n",
      "id": "nresearch-8"
    }
  ]
}
