{
  "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": "# Develop an Aner neural network\n\nIris: Fisher (1936), UCI, CC BY 4.0. Split before fitting normalization. This notebook uses native Aner variables and records observations after each cell.\n\nIn VS Code choose **Inspector** for variables, object references, and recorded loss. **Open Development Training Report** shows topology and available gradients. Dev mode is saved in this example; choose **Prod**, save, and rerun setup cells when the model is ready.\n"
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": "## Configure layers, initialization, loss, and optimizer\n"
    },
    {
      "cell_type": "code",
      "metadata": {},
      "source": [
        "import aner.dataset\n",
        "import aner.nn\n",
        "import aner.ml\n",
        "import aner.dev\n",
        "\n",
        "let split = dataset.iris().split(test: 0.2, seed: 2026)\n",
        "let network = nn.sequential(seed: 42)\n",
        "    .dense(inputs: 4, outputs: 8,\n",
        "           weights: nn.random(4, 8, seed: 7, scale: 0.25),\n",
        "           bias: nn.zeros(1, 8))\n",
        "    .tanh()\n",
        "    .dense(inputs: 8, outputs: 3)\n",
        "let pipeline = ml.classifier(network, standardize: true,\n",
        "                             loss: \"cross_entropy\", optimizer: \"sgd\")\n",
        "print(network.summary())\n",
        "print(pipeline.summary())\n"
      ],
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": "## Partial training\n\n400 full batch SGD updates; initial and final states are captured.\n"
    },
    {
      "cell_type": "code",
      "metadata": {},
      "source": [
        "let fitted = pipeline.fit(split.train(), epochs: 400, rate: 0.1)\n",
        "dev.capture(\"Trained model\", fitted)\n"
      ],
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": "## Evaluate held out rows\n\nThe training scaler is reused; this does not fit on the test set.\n"
    },
    {
      "cell_type": "code",
      "metadata": {},
      "source": [
        "print(fitted.evaluate(split.test()).summary())\n"
      ],
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": "## Continue from the trained parameters\n\nThe previous fitted model is unchanged; the same scaler is reused.\n"
    },
    {
      "cell_type": "code",
      "metadata": {},
      "source": [
        "let continued = pipeline.warm_start(fitted).fit(split.train(), epochs: 100, rate: 0.1)\n",
        "print(continued.evaluate(split.test()).summary())\n"
      ],
      "execution_count": null,
      "outputs": []
    }
  ]
}
