{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# 🧠⇌ 💾 Import / export between toolchains with NIR\n",
"\n",
"**BETA INFORMATION. SUBJECT TO API CHANGE.**\n",
"\n",
"Neuromorphic Intermediate Representation (NIR for short) is a new open-source package for interoperability between the new crop of SNN simulators. Rockpool supports import and export of (`torch`-backed) models using NIR.\n",
"\n",
""
]
},
{
"cell_type": "raw",
"metadata": {
"raw_mimetype": "text/restructuredtext",
"vscode": {
"languageId": "raw"
}
},
"source": [
"These are supported using the :py:func:`.nn.modules.to_nir` and :py:func:`.nn.modules.from_nir` functions from the :py:mod:`rockpool.nn.modules.torch` package.\n",
"\n",
"Using NIR requires the ``nir``, ``nirtorch`` and ``torch`` dependencies.\n",
"These can be installed alongside Rockpool with::\n",
"\n",
"\n",
" pip install 'rockpool[nir]'\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"This notebook shows you how to interact with NIR.\n",
"Let's start by generating a simple network.\n",
"\n",
"## Export from Rockpool to NIR"
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"
TorchSequential with shape (1, 4) {\n", " LinearTorch '0_LinearTorch' with shape (1, 2)\n", " LIFTorch '1_LIFTorch' with shape (2, 2)\n", " LinearTorch '2_LinearTorch' with shape (2, 4)\n", " LIFTorch '3_LIFTorch' with shape (4, 4)\n", "}\n", "\n" ], "text/plain": [ "TorchSequential with shape \u001b[1m(\u001b[0m\u001b[1;36m1\u001b[0m, \u001b[1;36m4\u001b[0m\u001b[1m)\u001b[0m \u001b[1m{\u001b[0m\n", " LinearTorch \u001b[32m'0_LinearTorch'\u001b[0m with shape \u001b[1m(\u001b[0m\u001b[1;36m1\u001b[0m, \u001b[1;36m2\u001b[0m\u001b[1m)\u001b[0m\n", " LIFTorch \u001b[32m'1_LIFTorch'\u001b[0m with shape \u001b[1m(\u001b[0m\u001b[1;36m2\u001b[0m, \u001b[1;36m2\u001b[0m\u001b[1m)\u001b[0m\n", " LinearTorch \u001b[32m'2_LinearTorch'\u001b[0m with shape \u001b[1m(\u001b[0m\u001b[1;36m2\u001b[0m, \u001b[1;36m4\u001b[0m\u001b[1m)\u001b[0m\n", " LIFTorch \u001b[32m'3_LIFTorch'\u001b[0m with shape \u001b[1m(\u001b[0m\u001b[1;36m4\u001b[0m, \u001b[1;36m4\u001b[0m\u001b[1m)\u001b[0m\n", "\u001b[1m}\u001b[0m\n" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "# - Import modules to build a simple network\n", "from rockpool.nn.modules import LIFTorch, LinearTorch\n", "from rockpool.nn.combinators import Sequential\n", "\n", "try:\n", " from rich import print\n", "except:\n", " pass\n", "\n", "net = Sequential(\n", " LinearTorch((1, 2)),\n", " LIFTorch(2),\n", " LinearTorch((2, 4)),\n", " LIFTorch(4),\n", ")\n", "print(net)" ] }, { "cell_type": "raw", "metadata": { "raw_mimetype": "text/restructuredtext", "vscode": { "languageId": "raw" } }, "source": [ "To handle import and export, Rockpool provides the helper functions :py:func:`.from_nir` and :py:func:`.to_nir`.\n", "Let's convert our Rockpool network to a NIR representation, and write it out to disk." ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
NIRGraph(\n", " nodes={\n", " 'input': Input(input_type={'input': array([1, 1])}),\n", " '0_LinearTorch': Linear(weight=tensor([[-1.5277],\n", " [-2.2684]])),\n", " '1_LIFTorch': CubaLIF(\n", " tau_syn=array([0.02, 0.02], dtype=float32),\n", " tau_mem=array([0.02, 0.02], dtype=float32),\n", " r=array([19.024588, 19.024588], dtype=float32),\n", " v_leak=array([0., 0.], dtype=float32),\n", " v_threshold=array([1., 1.], dtype=float32),\n", " w_in=array([1., 1.], dtype=float32),\n", " input_type={'input': array([2])},\n", " output_type={'output': array([2])},\n", " metadata={}\n", " ),\n", " '2_LinearTorch': Linear(\n", " weight=tensor([[-0.4406, 0.1872],\n", " [ 0.2237, -1.0186],\n", " [ 0.2433, 0.9899],\n", " [-1.5922, 0.0632]])\n", " ),\n", " '3_LIFTorch': CubaLIF(\n", " tau_syn=array([0.02, 0.02, 0.02, 0.02], dtype=float32),\n", " tau_mem=array([0.02, 0.02, 0.02, 0.02], dtype=float32),\n", " r=array([19.024588, 19.024588, 19.024588, 19.024588], dtype=float32),\n", " v_leak=array([0., 0., 0., 0.], dtype=float32),\n", " v_threshold=array([1., 1., 1., 1.], dtype=float32),\n", " w_in=array([1., 1., 1., 1.], dtype=float32),\n", " input_type={'input': array([4])},\n", " output_type={'output': array([4])},\n", " metadata={}\n", " ),\n", " 'output': Output(output_type={'output': array([1, 1, 4])})\n", " },\n", " edges=[\n", " ('input', '0_LinearTorch'),\n", " ('0_LinearTorch', '1_LIFTorch'),\n", " ('3_LIFTorch', 'output'),\n", " ('2_LinearTorch', '3_LIFTorch'),\n", " ('1_LIFTorch', '2_LinearTorch')\n", " ],\n", " input_type={'input': {'input': array([1, 1])}},\n", " output_type={'output': {'output': array([1, 1, 4])}},\n", " metadata={}\n", ")\n", "\n" ], "text/plain": [ "\u001b[1;35mNIRGraph\u001b[0m\u001b[1m(\u001b[0m\n", " \u001b[33mnodes\u001b[0m=\u001b[1m{\u001b[0m\n", " \u001b[32m'input'\u001b[0m: \u001b[1;35mInput\u001b[0m\u001b[1m(\u001b[0m\u001b[33minput_type\u001b[0m=\u001b[1m{\u001b[0m\u001b[32m'input'\u001b[0m: \u001b[1;35marray\u001b[0m\u001b[1m(\u001b[0m\u001b[1m[\u001b[0m\u001b[1;36m1\u001b[0m, \u001b[1;36m1\u001b[0m\u001b[1m]\u001b[0m\u001b[1m)\u001b[0m\u001b[1m}\u001b[0m\u001b[1m)\u001b[0m,\n", " \u001b[32m'0_LinearTorch'\u001b[0m: \u001b[1;35mLinear\u001b[0m\u001b[1m(\u001b[0m\u001b[33mweight\u001b[0m=\u001b[1;35mtensor\u001b[0m\u001b[1m(\u001b[0m\u001b[1m[\u001b[0m\u001b[1m[\u001b[0m\u001b[1;36m-1.5277\u001b[0m\u001b[1m]\u001b[0m,\n", " \u001b[1m[\u001b[0m\u001b[1;36m-2.2684\u001b[0m\u001b[1m]\u001b[0m\u001b[1m]\u001b[0m\u001b[1m)\u001b[0m\u001b[1m)\u001b[0m,\n", " \u001b[32m'1_LIFTorch'\u001b[0m: \u001b[1;35mCubaLIF\u001b[0m\u001b[1m(\u001b[0m\n", " \u001b[33mtau_syn\u001b[0m=\u001b[1;35marray\u001b[0m\u001b[1m(\u001b[0m\u001b[1m[\u001b[0m\u001b[1;36m0.02\u001b[0m, \u001b[1;36m0.02\u001b[0m\u001b[1m]\u001b[0m, \u001b[33mdtype\u001b[0m=\u001b[35mfloat32\u001b[0m\u001b[1m)\u001b[0m,\n", " \u001b[33mtau_mem\u001b[0m=\u001b[1;35marray\u001b[0m\u001b[1m(\u001b[0m\u001b[1m[\u001b[0m\u001b[1;36m0.02\u001b[0m, \u001b[1;36m0.02\u001b[0m\u001b[1m]\u001b[0m, \u001b[33mdtype\u001b[0m=\u001b[35mfloat32\u001b[0m\u001b[1m)\u001b[0m,\n", " \u001b[33mr\u001b[0m=\u001b[1;35marray\u001b[0m\u001b[1m(\u001b[0m\u001b[1m[\u001b[0m\u001b[1;36m19.024588\u001b[0m, \u001b[1;36m19.024588\u001b[0m\u001b[1m]\u001b[0m, \u001b[33mdtype\u001b[0m=\u001b[35mfloat32\u001b[0m\u001b[1m)\u001b[0m,\n", " \u001b[33mv_leak\u001b[0m=\u001b[1;35marray\u001b[0m\u001b[1m(\u001b[0m\u001b[1m[\u001b[0m\u001b[1;36m0\u001b[0m., \u001b[1;36m0\u001b[0m.\u001b[1m]\u001b[0m, \u001b[33mdtype\u001b[0m=\u001b[35mfloat32\u001b[0m\u001b[1m)\u001b[0m,\n", " \u001b[33mv_threshold\u001b[0m=\u001b[1;35marray\u001b[0m\u001b[1m(\u001b[0m\u001b[1m[\u001b[0m\u001b[1;36m1\u001b[0m., \u001b[1;36m1\u001b[0m.\u001b[1m]\u001b[0m, \u001b[33mdtype\u001b[0m=\u001b[35mfloat32\u001b[0m\u001b[1m)\u001b[0m,\n", " \u001b[33mw_in\u001b[0m=\u001b[1;35marray\u001b[0m\u001b[1m(\u001b[0m\u001b[1m[\u001b[0m\u001b[1;36m1\u001b[0m., \u001b[1;36m1\u001b[0m.\u001b[1m]\u001b[0m, \u001b[33mdtype\u001b[0m=\u001b[35mfloat32\u001b[0m\u001b[1m)\u001b[0m,\n", " \u001b[33minput_type\u001b[0m=\u001b[1m{\u001b[0m\u001b[32m'input'\u001b[0m: \u001b[1;35marray\u001b[0m\u001b[1m(\u001b[0m\u001b[1m[\u001b[0m\u001b[1;36m2\u001b[0m\u001b[1m]\u001b[0m\u001b[1m)\u001b[0m\u001b[1m}\u001b[0m,\n", " \u001b[33moutput_type\u001b[0m=\u001b[1m{\u001b[0m\u001b[32m'output'\u001b[0m: \u001b[1;35marray\u001b[0m\u001b[1m(\u001b[0m\u001b[1m[\u001b[0m\u001b[1;36m2\u001b[0m\u001b[1m]\u001b[0m\u001b[1m)\u001b[0m\u001b[1m}\u001b[0m,\n", " \u001b[33mmetadata\u001b[0m=\u001b[1m{\u001b[0m\u001b[1m}\u001b[0m\n", " \u001b[1m)\u001b[0m,\n", " \u001b[32m'2_LinearTorch'\u001b[0m: \u001b[1;35mLinear\u001b[0m\u001b[1m(\u001b[0m\n", " \u001b[33mweight\u001b[0m=\u001b[1;35mtensor\u001b[0m\u001b[1m(\u001b[0m\u001b[1m[\u001b[0m\u001b[1m[\u001b[0m\u001b[1;36m-0.4406\u001b[0m, \u001b[1;36m0.1872\u001b[0m\u001b[1m]\u001b[0m,\n", " \u001b[1m[\u001b[0m \u001b[1;36m0.2237\u001b[0m, \u001b[1;36m-1.0186\u001b[0m\u001b[1m]\u001b[0m,\n", " \u001b[1m[\u001b[0m \u001b[1;36m0.2433\u001b[0m, \u001b[1;36m0.9899\u001b[0m\u001b[1m]\u001b[0m,\n", " \u001b[1m[\u001b[0m\u001b[1;36m-1.5922\u001b[0m, \u001b[1;36m0.0632\u001b[0m\u001b[1m]\u001b[0m\u001b[1m]\u001b[0m\u001b[1m)\u001b[0m\n", " \u001b[1m)\u001b[0m,\n", " \u001b[32m'3_LIFTorch'\u001b[0m: \u001b[1;35mCubaLIF\u001b[0m\u001b[1m(\u001b[0m\n", " \u001b[33mtau_syn\u001b[0m=\u001b[1;35marray\u001b[0m\u001b[1m(\u001b[0m\u001b[1m[\u001b[0m\u001b[1;36m0.02\u001b[0m, \u001b[1;36m0.02\u001b[0m, \u001b[1;36m0.02\u001b[0m, \u001b[1;36m0.02\u001b[0m\u001b[1m]\u001b[0m, \u001b[33mdtype\u001b[0m=\u001b[35mfloat32\u001b[0m\u001b[1m)\u001b[0m,\n", " \u001b[33mtau_mem\u001b[0m=\u001b[1;35marray\u001b[0m\u001b[1m(\u001b[0m\u001b[1m[\u001b[0m\u001b[1;36m0.02\u001b[0m, \u001b[1;36m0.02\u001b[0m, \u001b[1;36m0.02\u001b[0m, \u001b[1;36m0.02\u001b[0m\u001b[1m]\u001b[0m, \u001b[33mdtype\u001b[0m=\u001b[35mfloat32\u001b[0m\u001b[1m)\u001b[0m,\n", " \u001b[33mr\u001b[0m=\u001b[1;35marray\u001b[0m\u001b[1m(\u001b[0m\u001b[1m[\u001b[0m\u001b[1;36m19.024588\u001b[0m, \u001b[1;36m19.024588\u001b[0m, \u001b[1;36m19.024588\u001b[0m, \u001b[1;36m19.024588\u001b[0m\u001b[1m]\u001b[0m, \u001b[33mdtype\u001b[0m=\u001b[35mfloat32\u001b[0m\u001b[1m)\u001b[0m,\n", " \u001b[33mv_leak\u001b[0m=\u001b[1;35marray\u001b[0m\u001b[1m(\u001b[0m\u001b[1m[\u001b[0m\u001b[1;36m0\u001b[0m., \u001b[1;36m0\u001b[0m., \u001b[1;36m0\u001b[0m., \u001b[1;36m0\u001b[0m.\u001b[1m]\u001b[0m, \u001b[33mdtype\u001b[0m=\u001b[35mfloat32\u001b[0m\u001b[1m)\u001b[0m,\n", " \u001b[33mv_threshold\u001b[0m=\u001b[1;35marray\u001b[0m\u001b[1m(\u001b[0m\u001b[1m[\u001b[0m\u001b[1;36m1\u001b[0m., \u001b[1;36m1\u001b[0m., \u001b[1;36m1\u001b[0m., \u001b[1;36m1\u001b[0m.\u001b[1m]\u001b[0m, \u001b[33mdtype\u001b[0m=\u001b[35mfloat32\u001b[0m\u001b[1m)\u001b[0m,\n", " \u001b[33mw_in\u001b[0m=\u001b[1;35marray\u001b[0m\u001b[1m(\u001b[0m\u001b[1m[\u001b[0m\u001b[1;36m1\u001b[0m., \u001b[1;36m1\u001b[0m., \u001b[1;36m1\u001b[0m., \u001b[1;36m1\u001b[0m.\u001b[1m]\u001b[0m, \u001b[33mdtype\u001b[0m=\u001b[35mfloat32\u001b[0m\u001b[1m)\u001b[0m,\n", " \u001b[33minput_type\u001b[0m=\u001b[1m{\u001b[0m\u001b[32m'input'\u001b[0m: \u001b[1;35marray\u001b[0m\u001b[1m(\u001b[0m\u001b[1m[\u001b[0m\u001b[1;36m4\u001b[0m\u001b[1m]\u001b[0m\u001b[1m)\u001b[0m\u001b[1m}\u001b[0m,\n", " \u001b[33moutput_type\u001b[0m=\u001b[1m{\u001b[0m\u001b[32m'output'\u001b[0m: \u001b[1;35marray\u001b[0m\u001b[1m(\u001b[0m\u001b[1m[\u001b[0m\u001b[1;36m4\u001b[0m\u001b[1m]\u001b[0m\u001b[1m)\u001b[0m\u001b[1m}\u001b[0m,\n", " \u001b[33mmetadata\u001b[0m=\u001b[1m{\u001b[0m\u001b[1m}\u001b[0m\n", " \u001b[1m)\u001b[0m,\n", " \u001b[32m'output'\u001b[0m: \u001b[1;35mOutput\u001b[0m\u001b[1m(\u001b[0m\u001b[33moutput_type\u001b[0m=\u001b[1m{\u001b[0m\u001b[32m'output'\u001b[0m: \u001b[1;35marray\u001b[0m\u001b[1m(\u001b[0m\u001b[1m[\u001b[0m\u001b[1;36m1\u001b[0m, \u001b[1;36m1\u001b[0m, \u001b[1;36m4\u001b[0m\u001b[1m]\u001b[0m\u001b[1m)\u001b[0m\u001b[1m}\u001b[0m\u001b[1m)\u001b[0m\n", " \u001b[1m}\u001b[0m,\n", " \u001b[33medges\u001b[0m=\u001b[1m[\u001b[0m\n", " \u001b[1m(\u001b[0m\u001b[32m'input'\u001b[0m, \u001b[32m'0_LinearTorch'\u001b[0m\u001b[1m)\u001b[0m,\n", " \u001b[1m(\u001b[0m\u001b[32m'0_LinearTorch'\u001b[0m, \u001b[32m'1_LIFTorch'\u001b[0m\u001b[1m)\u001b[0m,\n", " \u001b[1m(\u001b[0m\u001b[32m'3_LIFTorch'\u001b[0m, \u001b[32m'output'\u001b[0m\u001b[1m)\u001b[0m,\n", " \u001b[1m(\u001b[0m\u001b[32m'2_LinearTorch'\u001b[0m, \u001b[32m'3_LIFTorch'\u001b[0m\u001b[1m)\u001b[0m,\n", " \u001b[1m(\u001b[0m\u001b[32m'1_LIFTorch'\u001b[0m, \u001b[32m'2_LinearTorch'\u001b[0m\u001b[1m)\u001b[0m\n", " \u001b[1m]\u001b[0m,\n", " \u001b[33minput_type\u001b[0m=\u001b[1m{\u001b[0m\u001b[32m'input'\u001b[0m: \u001b[1m{\u001b[0m\u001b[32m'input'\u001b[0m: \u001b[1;35marray\u001b[0m\u001b[1m(\u001b[0m\u001b[1m[\u001b[0m\u001b[1;36m1\u001b[0m, \u001b[1;36m1\u001b[0m\u001b[1m]\u001b[0m\u001b[1m)\u001b[0m\u001b[1m}\u001b[0m\u001b[1m}\u001b[0m,\n", " \u001b[33moutput_type\u001b[0m=\u001b[1m{\u001b[0m\u001b[32m'output'\u001b[0m: \u001b[1m{\u001b[0m\u001b[32m'output'\u001b[0m: \u001b[1;35marray\u001b[0m\u001b[1m(\u001b[0m\u001b[1m[\u001b[0m\u001b[1;36m1\u001b[0m, \u001b[1;36m1\u001b[0m, \u001b[1;36m4\u001b[0m\u001b[1m]\u001b[0m\u001b[1m)\u001b[0m\u001b[1m}\u001b[0m\u001b[1m}\u001b[0m,\n", " \u001b[33mmetadata\u001b[0m=\u001b[1m{\u001b[0m\u001b[1m}\u001b[0m\n", "\u001b[1m)\u001b[0m\n" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "# - Import utilities to import and export NIR graphs\n", "from rockpool.nn.modules import from_nir, to_nir\n", "import nir\n", "import torch\n", "\n", "# - Convert the Rockpool network to the NIR representation\n", "nir_graph = to_nir(net)\n", "print(nir_graph)\n", "\n", "# - Write the exported graph to disk\n", "nir.write('rockpool.nir', nir_graph)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Import from NIR to Rockpool and deploy" ] }, { "cell_type": "raw", "metadata": { "raw_mimetype": "text/restructuredtext", "vscode": { "languageId": "raw" } }, "source": [ "Importing from NIR to Rockpool requires the :py:func:`.from_nir` helper function, along with ``nir.read``." ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
GraphExecutor(\n", " (0_LinearTorch): LinearTorch()\n", " (1_LIFTorch): LIFTorch()\n", " (2_LinearTorch): LinearTorch()\n", " (3_LIFTorch): LIFTorch()\n", " (input): Identity()\n", " (output): Identity()\n", ")\n", "\n" ], "text/plain": [ "\u001b[1;35mGraphExecutor\u001b[0m\u001b[1m(\u001b[0m\n", " \u001b[1m(\u001b[0m0_LinearTorch\u001b[1m)\u001b[0m: \u001b[1;35mLinearTorch\u001b[0m\u001b[1m(\u001b[0m\u001b[1m)\u001b[0m\n", " \u001b[1m(\u001b[0m1_LIFTorch\u001b[1m)\u001b[0m: \u001b[1;35mLIFTorch\u001b[0m\u001b[1m(\u001b[0m\u001b[1m)\u001b[0m\n", " \u001b[1m(\u001b[0m2_LinearTorch\u001b[1m)\u001b[0m: \u001b[1;35mLinearTorch\u001b[0m\u001b[1m(\u001b[0m\u001b[1m)\u001b[0m\n", " \u001b[1m(\u001b[0m3_LIFTorch\u001b[1m)\u001b[0m: \u001b[1;35mLIFTorch\u001b[0m\u001b[1m(\u001b[0m\u001b[1m)\u001b[0m\n", " \u001b[1m(\u001b[0minput\u001b[1m)\u001b[0m: \u001b[1;35mIdentity\u001b[0m\u001b[1m(\u001b[0m\u001b[1m)\u001b[0m\n", " \u001b[1m(\u001b[0moutput\u001b[1m)\u001b[0m: \u001b[1;35mIdentity\u001b[0m\u001b[1m(\u001b[0m\u001b[1m)\u001b[0m\n", "\u001b[1m)\u001b[0m\n" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "# - Read a NIR file from disk\n", "nir_graph = nir.read('rockpool.nir')\n", "\n", "# - Use `from_nir` to convert to Rockpool\n", "torch_net = from_nir(nir_graph)\n", "\n", "# - Alternatively, load and convert directly\n", "torch_net = from_nir('rockpool.nir')\n", "print(torch_net)" ] }, { "cell_type": "raw", "metadata": { "raw_mimetype": "text/restructuredtext", "vscode": { "languageId": "raw" } }, "source": [ "Note that ``torch_net`` is a ``torch.nn.Module``, and not a Rockpool-native module.\n", "This is a limitation caused by relying on the ``nirtorch`` package for NIR import.\n", "Nevertheless, this object contains Rockpool modules :py:class:`.LinearTorch` and :py:class:`.LIFTorch`, and can be simulated.\n", "Since it is a ``nirtorch.GraphExecutor`` module, it returns a tuple ``(output, state)``." ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [], "source": [ "# - Simulate the module\n", "output, state = torch_net(torch.rand(1, 100, 1))" ] }, { "cell_type": "raw", "metadata": { "raw_mimetype": "text/restructuredtext", "vscode": { "languageId": "raw" } }, "source": [ "It also supports the Rockpool :py:meth:`~.Module.as_graph` method, required for deployment." ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "XyloSim with shape (16, 1000, 8)" ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "from rockpool.devices.xylo.syns61201 import mapper, config_from_specification, XyloSim\n", "from rockpool.transform.quantize_methods import channel_quantize\n", "\n", "# - Map, quantize and get a Xylo HW configuration\n", "spec = mapper(torch_net.as_graph())\n", "config, is_valid, msg = config_from_specification(**channel_quantize(**spec))\n", "\n", "# - Produce a Xylo simulation matching the NIR graph\n", "XyloSim.from_config(config)" ] }, { "cell_type": "markdown", "metadata": { "vscode": { "languageId": "raw" } }, "source": [ "## See also\n", "For more information about NIR, as well as how NIR integrates with other libraries, see https://neuroir.org." ] } ], "metadata": { "kernelspec": { "display_name": "py38", "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.10.14" } }, "nbformat": 4, "nbformat_minor": 2 }