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