{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Collect Runtime Statistics with `Accountant`" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The `Accountant` module can collect runtime statistics. It uses\n", "the observer pattern: once an `Accountant` is registered to an\n", "`Algorithm`, events reported by the `Algorithm` may handlers \n", "\n", "This module is useful when the algorithm has a complicated `.step(..)`.\n", "Otherwise, it is always possible to collect information by inspecting\n", "the `Algorithm` in between iterations.\n", "\n", "Running this tutorial requires `matplotlib`." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Construct Algorithm\n", "\n", "To begin, consider a simple GA with the following configuration:\n", "\n", "| Component | Guide |\n", "| ----------- | ---------------------------------------------- |\n", "|`Individual`|Binary string|\n", "|`Evaluator`|OneMax|\n", "|`Selector`|Elitist truncation|\n", "|`Variator`|Mutation|\n", "\n", "Use a population size of 100 and individual size of 50 bits.\n", "EvoKit has all building blocks for this algorithm; for convenience,\n", "automate its creation with a function:" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "from evokit.core import Population\n", "from evokit.evolvables.algorithms import SimpleLinearAlgorithm\n", "from evokit.evolvables.selectors import TruncationSelector, Elitist\n", "from evokit.evolvables.binstring import BinaryString, CountBits, MutateBits\n", "\n", "IND_SIZE: int = 50\n", "POP_SIZE: int = 100\n", "MUTATE_P: float = 0.01\n", "\n", "def make_algo() -> SimpleLinearAlgorithm[BinaryString]:\n", " pop: Population[BinaryString] = Population(\n", " BinaryString.random(IND_SIZE) for _ in range(POP_SIZE))\n", " return SimpleLinearAlgorithm(population=pop,\n", " variator=MutateBits(MUTATE_P),\n", " evaluator=CountBits(),\n", " selector=Elitist(TruncationSelector(POP_SIZE)))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Because `CanonicalGeneticAlgorithm` has only one population,\n", "this attribute can be accessed as `.population`. Operators of\n", "this algorithm are not stateless and do not have much to offer\n", "in terms of analytics." ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [], "source": [ "import matplotlib.pyplot as plt" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## The Manual Approach\n", "\n", "For a simple example, collect then plot the fitness curve by generation:" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [], "source": [ "STEP_COUNT: int = 30\n", "\n", "algo = make_algo()\n", "best_fitnesses: list[float] = []\n", "\n", "for _ in range(STEP_COUNT):\n", " algo.step()\n", " best_fitnesses.append(algo.population.best().fitness[0])" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "Text(0, 0.5, 'Best fitness')" ] }, "execution_count": 4, "metadata": {}, "output_type": "execute_result" }, { "data": { "image/png": "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/elPNWHCBEn15eirr75q9JqwsDA5nc7vPM+ll16qTz/9VLfcckujc6enp3uUB0DroNAAaLJ//OMfuuqqq3TZZZfp8ccfV0ZGhoKCgrR+/Xrt2LFD2dnZGjFihHJycnTdddfpT3/6ky655BKVlJTo7bff1oQJE84aIjqXmJgY/frXv9a0adPkcrn0/e9/XzabTZ9++qmsVmujkvFtvXv31uLFizVu3DhZLBY9+uijZ10x6d69u1avXq0bb7xR4eHh6tix41nneeCBB3TDDTdo0KBBGjFihJYtW6bFixc3umMKgO+g0ABosl69eqmoqEhPPfWUpk+froMHDyo8PFzp6en69a9/rbvuuksWi0XvvPOOHnnkEU2dOlVHjhxRYmKihgwZos6dOzf5e/3+979XQkKCZs6cqb179youLk5ZWVn6zW9+851/7i9/+Yt+9rOf6corr1THjh310EMPyW63N3rNE088oTvuuEO9evWSw+GQYRhnnee6667T7Nmz9cwzz+jee+9Vjx49NH/+fA0dOrTJPwOA1mMxzvV/MgAAgB9hHRoAAOD3KDQAAMDvUWgAAIDfo9AAAAC/R6EBAAB+j0IDAAD8HoUGAAD4PQoNAADwexQaAADg9yg0AADA71FoAACA3/v/2+IbGLbyP90AAAAASUVORK5CYII=", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "plt.plot(range(STEP_COUNT), best_fitnesses) #type: ignore[reportUnknownMemberType]\n", "plt.xlabel(\"Generation\") #type: ignore[reportUnknownMemberType]\n", "plt.ylabel(\"Best fitness\") #type: ignore[reportUnknownMemberType]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Automating with Accountant\n", "\n", "In `accounting`, the `.Accountant` module automates statistics collection.\n", "`accounting.accountants` provides several simple accountants for reference.\n", "In addition, `accounting.visualisers` offers a suite of utilities\n", "to plot collected data.\n", "\n", "Instead of using a stock accountant, let's build our own!" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Inspecting Available Events\n", "\n", "To create an accountant for an algorithm, it's best to check what\n", "event the algorithm could report. An algorithm declares its standard\n", "events in `.events`.\n", "Furthermore, the base class `Algorithm` fires two events automatically:\n", "`STEP_BEGIN` before `.step(..)` and `STEP_END` after. These events are\n", "declared in `.automatic_events`.\n", "\n", "Check which events the SimpleLinearAlgorithm could report:" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "events: ['POST_VARIATION', 'POST_EVALUATION', 'POST_SELECTION']; automatic events: ['STEP_BEGIN', 'STEP_END']\n" ] } ], "source": [ "algo_2 = make_algo()\n", "print(f\"events: {algo_2.events}; automatic events: {algo_2.automatic_events}\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Crafting an Accountant\n", "An accountant must be created with `accounting.Accountant`.\n", "The constructor takes three parameters: (a) a list of `events`\n", "that can trigger collection, (b) a callable `handler` that collects\n", "data from the associated algorithm, and (c) an optional parameter\n", "that controls if the accountant should also `watch_automatic_events`.\n", "\n", "For simplicity, declare an `Accountant` that collects the best fitness\n", "from a population only on automatic events. Observe the signature:\n", "the accountant collects...\n", "\n", "* ... from a `HomogeneousAlgorithm` (`Algorithm` with one `.population`)\n", "of `BinaryString`s,\n", "* a `tuple` of one `float` that contains a fitness value.\n", "\n", "An algorithm can register several accountants, which are\n", "updated in order or registration. To check if the accountant\n", "is registered, check if it is in `Algorithm.accountants`." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "from evokit.accounting import Accountant\n", "from evokit.evolvables.algorithms import HomogeneousAlgorithm" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [], "source": [ "fit_acc = Accountant[HomogeneousAlgorithm[BinaryString], tuple[float, ...]](\n", " events=[],\n", " handler=lambda algo: algo.population.best().fitness,\n", " watch_automatic_events=True)\n", "\n", "algo_2.register(fit_acc)\n", "assert(fit_acc in algo_2.accountants)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "To see how things work under the hood, fire an\n", "event in the algorithm, then check what the accountant\n", "has collected.\n", "\n", "Each record contains four values: (a) the event that triggered\n", "collection, (b) the generation in which the event is fired, the\n", "time (via `time.perf_timer`, in seconds) at which the event in fired,\n", "and (d) the collected value.\n", "\n", "Not all statistics are available at all times: for example, because\n", "the population starts off unevaluated, the best fitness is\n", "`(nan,)`." ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[AccountantRecord(event='STEP_BEGIN', generation=0, value=(nan,), time=443313.1574931)]\n" ] } ], "source": [ "algo_2.update(algo.automatic_events[0])\n", "print(fit_acc.report())" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now, wipe all records from `fit_acc` and see how\n", "it collects statistics from a running algorithm. Then, visualise\n", "the results with a function from `accounting.visualisers`:" ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [], "source": [ "fit_acc.purge()\n", "\n", "for _ in range(STEP_COUNT):\n", " algo_2.step()" ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [ { "data": { "image/png": "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7j4yMjLU2Ngot9stm80mSerfv7+2b9+uDRs26O9//7seeugh/fSnP9WWLVtUX18vSVqzZo2GDRvWppbdbpd0Olh0prq6WpI0aNCgc24LIPQIHwBCYvLkyfrzn/+skSNHKjGxax8t+fn5kqTdu3f7/yxJiYmJuvbaa3Xttdfq4YcfVlpamtavX6/p06fLbrerrKxMV155Zbs18/LytGzZMjU3N3c4+rFr1y4lJSVp/PjxAR0jgNBgwimAkPjud7+r6upqzZ07V1u2bNH+/fu1bt063XrrrfJ4PO22GTRokCZPnqx33nnH/9pf//pX/fd//7eKi4t18OBBPf/88/J6vTr//PPVv39//fCHP9R9992nZcuWaf/+/dq+fbuefvppLVu2TJJ09913y+l06uabb9bWrVu1d+9e/fGPf2xze/GmTZt0+eWXd2mUBEDoET4AhERWVpbeffddeTwezZgxQxMmTND3v/99paWlyWrt+KPmtttu04svvuj/e1paml599VVdffXVuvDCC/XMM8/oT3/6k3+U4rHHHtNPfvITFRYW6sILL9R1112nNWvWaNSoUZKkgQMHav369aqvr9eVV16pKVOm6Le//W2bUZAVK1bo9ttvD9OZAHAuLDIGIKpOnjyp888/Xy+99JIKCgrCvr+1a9fqBz/4gXbu3Nnly0MAQouRDwBR1bdvXz3//POdLkYWSg0NDXruuecIHkAUMfIBAAAiipEPAAAQUYQPAAAQUYQPAAAQUYQPAAAQUYQPAAAQUYQPAAAQUYQPAAAQUYQPAAAQUYQPAAAQUf8/Vil1RdkRsI0AAAAASUVORK5CYII=", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "from evokit.accounting.visualisers import plot\n", "\n", "plot(fit_acc.report(),\n", " track_generation=True,\n", " use_line=True,)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Notice that the visualiser highlights automatic events,\n", "which mark boundaries of generations. It also plots data points\n", "over runtime, which provides an intuitive view of training progression." ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.12.0" } }, "nbformat": 4, "nbformat_minor": 2 }