From 2e10b9145d5d9a5323b2a8355a712a3de07556e9 Mon Sep 17 00:00:00 2001
From: Vincent TEMPLIER <vincent.templier@cea.fr>
Date: Tue, 7 May 2024 09:45:53 +0000
Subject: [PATCH] Add example of MNIST fp32 export

---
 examples/README.md                            |   6 +
 examples/export_LeNet/export_lenet_fp32.ipynb | 290 ++++++++++++++++++
 2 files changed, 296 insertions(+)
 create mode 100644 examples/README.md
 create mode 100644 examples/export_LeNet/export_lenet_fp32.ipynb

diff --git a/examples/README.md b/examples/README.md
new file mode 100644
index 0000000..643f196
--- /dev/null
+++ b/examples/README.md
@@ -0,0 +1,6 @@
+# Examples on how to use this module Aidge ARM CortexM Export
+
+This folder contains some examples on how to use the `Aidge ARM CortexM Export` module in your projects.
+- [LeNet export for MNIST dataset](./export_LeNet/)
+
+Feel free to propose your own contributions with this module !
\ No newline at end of file
diff --git a/examples/export_LeNet/export_lenet_fp32.ipynb b/examples/export_LeNet/export_lenet_fp32.ipynb
new file mode 100644
index 0000000..c936492
--- /dev/null
+++ b/examples/export_LeNet/export_lenet_fp32.ipynb
@@ -0,0 +1,290 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "# Export a MNIST model to a CPP standalone project"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%pip install requests numpy ipywidgets ipycanvas"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Download the model"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import os\n",
+    "import requests"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "# Download onnx file if it has not been done before\n",
+    "if not os.path.isfile(\"./lenet_mnist.onnx\"):\n",
+    "    response = requests.get(\"https://huggingface.co/vtemplier/LeNet_MNIST/resolve/main/lenet_mnist.onnx?download=true\")\n",
+    "    if response.status_code == 200:\n",
+    "        with open(\"lenet_mnist.onnx\", 'wb') as f:\n",
+    "            f.write(response.content)\n",
+    "        print(\"ONNX model downloaded successfully.\")\n",
+    "    else:\n",
+    "        print(\"Failed to download ONNX model. Status code:\", response.status_code)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Load the model in Aidge and manipulate it"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import aidge_core\n",
+    "import aidge_backend_cpu\n",
+    "import aidge_onnx\n",
+    "import aidge_export_cpp\n",
+    "import aidge_export_arm_cortexm"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "model = aidge_onnx.load_onnx(\"lenet_mnist.onnx\")"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "# Remove Flatten node, useless in the CPP export\n",
+    "aidge_core.remove_flatten(model)\n",
+    "\n",
+    "# Freeze the model by setting constant to parameters producers\n",
+    "for node in model.get_nodes():\n",
+    "    if node.type() == \"Producer\":\n",
+    "        node.get_operator().set_attr(\"Constant\", True)\n",
+    "\n",
+    "# Create Producer Node for the Graph\n",
+    "input_node = aidge_core.Producer([1, 1, 28, 28], \"input\")\n",
+    "input_node.add_child(model)\n",
+    "model.add(input_node) \n",
+    "\n",
+    "# Configuration for the model + forward dimensions\n",
+    "model.compile(\"cpu\", aidge_core.DataType.Float32)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "# Generate scheduling of the model\n",
+    "scheduler = aidge_core.SequentialScheduler(model)\n",
+    "scheduler.generate_scheduling()"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Export the model"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "aidge_export_arm_cortexm.export(\"lenet_export_fp32\", model, scheduler, board=\"stm32h7\")"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "### Draw your own number"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "from ipywidgets import HBox, VBox, Button, Layout\n",
+    "from ipycanvas import RoughCanvas, hold_canvas\n",
+    "\n",
+    "img_name = \"my_number.png\"\n",
+    "\n",
+    "canvas = RoughCanvas(width=28, height=28, sync_image_data=True)\n",
+    "\n",
+    "button_gen = Button(description=\"Generate PNG\")\n",
+    "button_clear = Button(description=\"Clear\")\n",
+    "\n",
+    "drawing = False\n",
+    "position = None\n",
+    "shape = []\n",
+    "\n",
+    "def on_erase_button_clicked(b):\n",
+    "    canvas.clear()\n",
+    "\n",
+    "def on_generate_button_clicked(b):\n",
+    "    try:\n",
+    "        canvas.to_file(img_name)\n",
+    "        print(f\"Image generated to {img_name} !\")\n",
+    "    except:\n",
+    "        print(\"Draw a number before generating the image.\")\n",
+    "\n",
+    "button_clear.on_click(on_erase_button_clicked)\n",
+    "button_gen.on_click(on_generate_button_clicked)\n",
+    "\n",
+    "def on_mouse_down(x, y):\n",
+    "    global drawing\n",
+    "    global position\n",
+    "    global shape\n",
+    "\n",
+    "    drawing = True\n",
+    "    position = (x, y)\n",
+    "    shape = [position]\n",
+    "\n",
+    "def on_mouse_move(x, y):\n",
+    "    global drawing\n",
+    "    global position\n",
+    "    global shape\n",
+    "\n",
+    "    if not drawing:\n",
+    "        return\n",
+    "\n",
+    "    with hold_canvas():\n",
+    "        canvas.stroke_line(position[0], position[1], x, y)\n",
+    "        position = (x, y)\n",
+    "\n",
+    "    shape.append(position)\n",
+    "\n",
+    "def on_mouse_up(x, y):\n",
+    "    global drawing\n",
+    "    global position\n",
+    "    global shape\n",
+    "\n",
+    "    drawing = False\n",
+    "\n",
+    "    with hold_canvas():\n",
+    "        canvas.stroke_line(position[0], position[1], x, y)\n",
+    "\n",
+    "    shape = []\n",
+    "\n",
+    "canvas.on_mouse_down(on_mouse_down)\n",
+    "canvas.on_mouse_move(on_mouse_move)\n",
+    "canvas.on_mouse_up(on_mouse_up)\n",
+    "\n",
+    "canvas.stroke_style = \"#000000\"\n",
+    "\n",
+    "VBox((canvas, HBox((button_gen, button_clear))), \n",
+    "     layout=Layout(height='auto', width=\"300px\"))"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "### Generate inputs for testing the model from your drawing"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "try:\n",
+    "    number_np = canvas.get_image_data()\n",
+    "    # We got a numpy array with the shape of (28,28,4)\n",
+    "    # Transform it to (28,28)\n",
+    "    x = number_np[:, :, 3].astype(\"float32\")\n",
+    "    # Convert from [0, 255] to [0, 1] and export it\n",
+    "    aidge_export_cpp.generate_input_file(export_folder=\"lenet_export_fp32\",\n",
+    "                                         array_name=\"inputs\",\n",
+    "                                         array=x / 255)\n",
+    "except:\n",
+    "    print(\"Please draw a number in the previous cell before running this one.\")"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "### Compile the export and test it"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "!cd lenet_export_fp32 && make"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "!./lenet_export_fp32/bin/run_export"
+   ]
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "env",
+   "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.8.10"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 2
+}
-- 
GitLab