From 6a76743420000d96d34d84f117164756c4710a56 Mon Sep 17 00:00:00 2001 From: Jon Nordby Date: Fri, 13 Dec 2024 21:10:01 +0100 Subject: [PATCH 1/9] pyproject: Add initial metadata to enable pip install --- pyproject.toml | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 pyproject.toml diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..86407ed --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,35 @@ + +[build-system] +requires = ["hatchling"] +build-backend = "hatchling.build" + +[tool.hatch.build.targets.wheel] +packages = ["src", "include", "tools" ] + +[tool.hatch.build.targets.wheel.sources] +"src" = "tinymaix/src" +"include" = "tinymaix/include" +"tools" = "tinymaix/tools" + +[project] +name = "TinyMaix" +readme = "README.md" +requires-python = ">= 3.8" +keywords = ["machine learning", "deep learning", "microcontroller", "embedded"] +version = "0.0.1" + +dependencies = [ + "keras<3.0.0", + "pillow>=10.0.0", +] + +classifiers = [ + "License :: OSI Approved :: Apache Software License", +] + + +[project.urls] +Homepage = "https://github.com/sipeed/TinyMaix" +Documentation = "https://github.com/sipeed/TinyMaix" +Repository = "https://github.com/sipeed/TinyMaix" + From 957c0093f46a8946b780523651d686a9b4926877 Mon Sep 17 00:00:00 2001 From: Jon Nordby Date: Fri, 13 Dec 2024 21:10:48 +0100 Subject: [PATCH 2/9] README: Mention how to install with pip --- README.md | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/README.md b/README.md index 427fa90..dcb7ee8 100644 --- a/README.md +++ b/README.md @@ -162,6 +162,27 @@ make ./mbnet ``` + +## How to install + +TinyMaix can be installed as a Python package + +``` +pip install git+https://github.com/sipeed/TinyMaix@master +``` + +TinyMaix requires [Tensorflow](https://www.tensorflow.org/) version `<= 2.14`. +There are multiple options for how to install this, see the TensorFlow documentation. + +For example: +``` +pip install 'tensorflow-cpu<=2.14.1' +``` + +NOTE: Tensorflow 2.14 supports up until Python 3.11. +However, *Python 3.12 is not supported* by Tensorflow 2.14. + + ## How to use (API) ### Load Model tm_err_t tm_load (tm_mdl_t* mdl, const uint8_t* bin, uint8_t*buf, tm_cb_t cb, tm_mat_t* in); From 75cc5eaf4e6df3069359af0d8f38922c59470d6c Mon Sep 17 00:00:00 2001 From: Jon Nordby Date: Fri, 13 Dec 2024 21:32:50 +0100 Subject: [PATCH 3/9] tflite2tmdl: Only use relative import Avoids exceptions inside tflite_reader.py being swallowed Requires that one runs with module load option, for example: python -m tools.tflite2tmdl OR python -m tinymaix.tflite2tmdl --- tools/tflite2tmdl.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/tools/tflite2tmdl.py b/tools/tflite2tmdl.py index 4e9c675..0e09658 100644 --- a/tools/tflite2tmdl.py +++ b/tools/tflite2tmdl.py @@ -18,11 +18,7 @@ import tensorflow as tf import time, struct from PIL import Image -try: - from .tflite_reader import read_tflite -except: - from tflite_reader import read_tflite - +from .tflite_reader import read_tflite # constant TM_MDL_INT8 = 0 From e4a5ea05f7a339a445819d521784d7cf01c6fc54 Mon Sep 17 00:00:00 2001 From: Jon Nordby Date: Fri, 13 Dec 2024 21:35:49 +0100 Subject: [PATCH 4/9] CI: Add initial Github Actions configuration --- .github/workflows/tests.yaml | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 .github/workflows/tests.yaml diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml new file mode 100644 index 0000000..8e2763b --- /dev/null +++ b/.github/workflows/tests.yaml @@ -0,0 +1,36 @@ +name: Python package + +on: [push, pull_request] + +jobs: + test: + + runs-on: ubuntu-latest + strategy: + matrix: + python-version: ["3.10"] + + steps: + - uses: actions/checkout@v2 + with: + submodules: true + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v2 + with: + python-version: ${{ matrix.python-version }} + + - name: Install OS dependencies + run: | + sudo apt-get install -yqq python-tk git + - name: Install Python dependencies + run: | + if [ -f requirements.txt ]; then pip install -r requirements.txt; fi + if [ -f requirements.dev.txt ]; then pip install -r requirements.dev.txt; fi + - name: Install as pip package + run: | + pip install ./ -v + - name: Test installed package + working-directory: examples/auto_test + run: | + python auto_test.py + From e2d1b8e6f6ca4e17ab97ed3701b11d41e11b7024 Mon Sep 17 00:00:00 2001 From: Jon Nordby Date: Fri, 13 Dec 2024 23:04:34 +0100 Subject: [PATCH 5/9] Add requirements.dev.txt file So it can be used by Github Actions (or developers locally) --- examples/auto_test/requirements.txt | 1 - requirements.dev.txt | 2 ++ 2 files changed, 2 insertions(+), 1 deletion(-) delete mode 100644 examples/auto_test/requirements.txt create mode 100644 requirements.dev.txt diff --git a/examples/auto_test/requirements.txt b/examples/auto_test/requirements.txt deleted file mode 100644 index 0f57144..0000000 --- a/examples/auto_test/requirements.txt +++ /dev/null @@ -1 +0,0 @@ -tensorflow diff --git a/requirements.dev.txt b/requirements.dev.txt new file mode 100644 index 0000000..691c5cd --- /dev/null +++ b/requirements.dev.txt @@ -0,0 +1,2 @@ +tensorflow-cpu==2.14.1 +numpy From 900e48b20211f83028b42d3c953c099aa78e750c Mon Sep 17 00:00:00 2001 From: Jon Nordby Date: Fri, 13 Dec 2024 21:41:18 +0100 Subject: [PATCH 6/9] auto_test: Make sure errors in running commands are shown --- examples/auto_test/auto_test.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/examples/auto_test/auto_test.py b/examples/auto_test/auto_test.py index 02c5cc0..9dc1f93 100644 --- a/examples/auto_test/auto_test.py +++ b/examples/auto_test/auto_test.py @@ -1,17 +1,19 @@ import os,sys,time -from subprocess import * -import datetime,time -import threading +import datetime +import subprocess + ### This script do auto testing before release code. test_list = ["mnist_f", "mnist_q", "mbnet_f", "mbnet_q"] def runcmd(cmd): - r=Popen(cmd,stdin=PIPE,stdout=PIPE,stderr=PIPE, shell=True) + + stdout = subprocess.check_output(cmd, shell=True) + # stdin=PIPE,stdout=PIPE,stderr=PIPE a=[] - for line in r.stdout.readlines(): - a.append(line.decode("utf8").strip()) + for line in stdout.decode("utf8").readlines(): + a.append(line.strip()) return a From 4a409cadf4fadf6513aa3a727e469627b58c88e6 Mon Sep 17 00:00:00 2001 From: Jon Nordby Date: Fri, 13 Dec 2024 22:54:19 +0100 Subject: [PATCH 7/9] auto_test: Remove code duplication between cases, use python -m for tools --- examples/auto_test/auto_test.py | 123 ++++++++++++++------------------ 1 file changed, 52 insertions(+), 71 deletions(-) diff --git a/examples/auto_test/auto_test.py b/examples/auto_test/auto_test.py index 9dc1f93..8a96fd1 100644 --- a/examples/auto_test/auto_test.py +++ b/examples/auto_test/auto_test.py @@ -7,15 +7,29 @@ test_list = ["mnist_f", "mnist_q", "mbnet_f", "mbnet_q"] -def runcmd(cmd): +def runcmd(cmd, cwd=None): - stdout = subprocess.check_output(cmd, shell=True) + stdout = subprocess.check_output(cmd, shell=True, cwd=cwd) # stdin=PIPE,stdout=PIPE,stderr=PIPE a=[] - for line in stdout.decode("utf8").readlines(): + for line in stdout.decode("utf8").strip().split('\n'): a.append(line.strip()) return a +def run_h5_to_tflite(cmd, **kwargs): + program = 'python -m tinymaix.tools.h5_to_tflite' + cmd = program + ' ' + cmd + return runcmd(cmd, **kwargs) + +def run_tflite2tmdl(cmd, **kwargs): + program = 'python -m tinymaix.tools.tflite2tmdl' + cmd = program + ' ' + cmd + return runcmd(cmd, **kwargs) + +tools_dir = '../../tools/' +mnist_dir = '../mnist' +mbnet_dir = '../mbnet' + print("This script only test INT8/FP32, you need change OPT0&OPT1") t00= time.time() @@ -24,25 +38,20 @@ def runcmd(cmd): t0= time.time() print("========Step1.1: test MNIST fp32") print("====Step1.1.1: MNIST fp32 cvt") - cmd="cd ../../tools/ && python3 h5_to_tflite.py h5/mnist_valid.h5 tflite/mnist_valid_f.tflite 0 && python3 tflite2tmdl.py tflite/mnist_valid_f.tflite tmdl/mnist_valid_f.tmdl fp32 1 28,28,1 10" - res = runcmd(cmd) - print(res[-1]) - if res[-1] == "Saved to tinymaix model header to tmdl/mnist_valid_f.h": - print("====Step1.1.1: OK~") - else: - print("====Step1.1.1: ERR!!!") - exit(-1) + run_h5_to_tflite("h5/mnist_valid.h5 tflite/mnist_valid_f.tflite 0", cwd=tools_dir) + res = run_tflite2tmdl("tflite/mnist_valid_f.tflite tmdl/mnist_valid_f.tmdl fp32 1 28,28,1 10", cwd=tools_dir) + assert 'Saved to tmdl/mnist_valid_f.tmdl' in res[-1], ('Step 1.1.1 ERR', res) + print("====Step1.1.2: MNIST fp32 compile&run") - cmd="cd ../mnist && sed -i 's/#define TM_MDL_TYPE TM_MDL_INT8/#define TM_MDL_TYPE TM_MDL_FP32/g' ../../include/tm_port.h && rm -rf build && mkdir build && cd build && cmake .. && make && ./mnist" - res = runcmd(cmd) + cmd="sed -i 's/#define TM_MDL_TYPE TM_MDL_INT8/#define TM_MDL_TYPE TM_MDL_FP32/g' ../../include/tm_port.h" + res = runcmd(cmd, cwd=mnist_dir) + res = runcmd("rm -rf build && mkdir build && cd build && cmake .. && make && ./mnist", cwd=mnist_dir) print(res[-1]) - if res[-1] == "### Predict output is: Number 2, prob 1.000": - print("====Step1.1.2: OK~") - runcmd("rm ../../tools/tmdl/mnist_valid_f.tmdl") #clean tmdl - else: - print("====Step1.1.2: ERR!!!") - exit(-2) + assert 'Predict output is: Number 2, prob 1.0' in res[-1], res[-1] + + runcmd("rm ../../tools/tmdl/mnist_valid_f.tmdl") #clean tmdl + t1= time.time() print("========Step1.1: test MNIST fp32 OK~ use %.1fs"%(t1-t0)) @@ -51,26 +60,17 @@ def runcmd(cmd): t0= time.time() print("========Step1.2: test MNIST int8") print("====Step1.2.1: MNIST int8 cvt") - cmd="cd ../../tools/ && python3 h5_to_tflite.py h5/mnist_valid.h5 tflite/mnist_valid_q.tflite 1 quant_img_mnist/ 0to1 && python3 tflite2tmdl.py tflite/mnist_valid_q.tflite tmdl/mnist_valid_q.tmdl int8 1 28,28,1 10" - res = runcmd(cmd) - print(res[-1]) - if res[-1] == "Saved to tinymaix model header to tmdl/mnist_valid_q.h": - print("====Step1.2.1: OK~") - else: - print("====Step1.2.1: ERR!!!") - exit(-1) + res = run_h5_to_tflite("h5/mnist_valid.h5 tflite/mnist_valid_q.tflite 1 quant_img_mnist/ 0to1", cwd=tools_dir) + res = run_tflite2tmdl("tflite/mnist_valid_q.tflite tmdl/mnist_valid_q.tmdl int8 1 28,28,1 10", cwd=tools_dir) print("====Step1.2.2: MNIST int8 compile&run") - - cmd="cd ../mnist && sed -i 's/#define TM_MDL_TYPE TM_MDL_FP32/#define TM_MDL_TYPE TM_MDL_INT8/g' ../../include/tm_port.h && rm -rf build && mkdir build && cd build && cmake .. && make && ./mnist" - res = runcmd(cmd) + cmd="sed -i 's/#define TM_MDL_TYPE TM_MDL_FP32/#define TM_MDL_TYPE TM_MDL_INT8/g' ../../include/tm_port.h" + res = runcmd(cmd, cwd=mnist_dir) + res = runcmd("rm -rf build && mkdir build && cd build && cmake .. && make && ./mnist", cwd=mnist_dir) print(res[-1]) - if res[-1] == "### Predict output is: Number 2, prob 0.996": - print("====Step1.2.2: OK~") - runcmd("rm ../../tools/tmdl/mnist_valid_q.tmdl") #clean tmdl - else: - print("====Step1.2.2: ERR!!!") - exit(-2) + assert 'Predict output is: Number 2, prob 0.996' in res[-1], res[-1] + + runcmd("rm ../../tools/tmdl/mnist_valid_q.tmdl") #clean tmdl t1= time.time() print("========Step1.2: test MNIST int8 OK~ use %.1fs"%(t1-t0)) @@ -81,27 +81,17 @@ def runcmd(cmd): t0= time.time() print("========Step2.1: test MBNET fp32") print("====Step2.1.1: MBNET fp32 cvt") - cmd="cd ../../tools/ && python3 h5_to_tflite.py h5/mbnet128_0.25.h5 tflite/mbnet128_0.25_f.tflite 0 && python3 tflite2tmdl.py tflite/mbnet128_0.25_f.tflite tmdl/mbnet128_0.25_f.tmdl fp32 1 128,128,3 1000" - res = runcmd(cmd) - print(res[-1]) - if res[-1] == "Saved to tinymaix model header to tmdl/mbnet128_0.25_f.h": - print("====Step2.1.1: OK~") - else: - print("====Step2.1.1: ERR!!!") - exit(-1) + res = run_h5_to_tflite("h5/mbnet128_0.25.h5 tflite/mbnet128_0.25_f.tflite 0", cwd=tools_dir) + res = run_tflite2tmdl("tflite/mbnet128_0.25_f.tflite tmdl/mbnet128_0.25_f.tmdl fp32 1 128,128,3 1000", cwd=tools_dir) print("====Step2.1.2: MBNET fp32 compile&run") - - cmd="cd ../mbnet && sed -i 's/#define TM_MDL_TYPE TM_MDL_INT8/#define TM_MDL_TYPE TM_MDL_FP32/g' ../../include/tm_port.h && rm -rf build && mkdir build && cd build && cmake .. && make && ./mbnet" - res = runcmd(cmd) + cmd="sed -i 's/#define TM_MDL_TYPE TM_MDL_INT8/#define TM_MDL_TYPE TM_MDL_FP32/g' ../../include/tm_port.h" + res = runcmd(cmd, cwd=mbnet_dir) + res = runcmd("rm -rf build && mkdir build && cd build && cmake .. && make && ./mbnet", cwd=mbnet_dir) print(res[-1]) - if res[-1] == "### Predict output is: Class 292 (tiger, Panthera tigris), Prob 0.866" or \ - res[-1] == "### Predict output is: Class 292 (tiger, Panthera tigris), Prob 0.891": - print("====Step2.1.2: OK~") - runcmd("rm ../../tools/tmdl/mbnet128_0.25_f.tmdl") #clean tmdl - else: - print("====Step2.1.2: ERR!!!") - exit(-2) + assert 'Class 292 (tiger, Panthera tigris), Prob 0.8' in res[-1], res[-1] + + runcmd("rm ../../tools/tmdl/mbnet128_0.25_f.tmdl") #clean tmdl t1= time.time() print("========Step2.1: test MBNET fp32 OK~ use %.1fs"%(t1-t0)) @@ -111,26 +101,17 @@ def runcmd(cmd): t0= time.time() print("========Step2.2: test MBNET int8") print("====Step2.2.1: MBNET int8 cvt") - cmd="cd ../../tools/ && python3 h5_to_tflite.py h5/mbnet128_0.25.h5 tflite/mbnet128_0.25_q.tflite 1 quant_img128/ 0to1 && python3 tflite2tmdl.py tflite/mbnet128_0.25_q.tflite tmdl/mbnet128_0.25_q.tmdl int8 1 128,128,3 1000" - res = runcmd(cmd) - print(res[-1]) - if res[-1] == "Saved to tinymaix model header to tmdl/mbnet128_0.25_q.h": - print("====Step2.2.1: OK~") - else: - print("====Step2.2.1: ERR!!!") - exit(-1) + res = run_h5_to_tflite("h5/mbnet128_0.25.h5 tflite/mbnet128_0.25_q.tflite 1 quant_img128/ 0to1", cwd=tools_dir) + res = run_tflite2tmdl("tflite/mbnet128_0.25_q.tflite tmdl/mbnet128_0.25_q.tmdl int8 1 128,128,3 1000", cwd=tools_dir) print("====Step2.2.2: MBNET int8 compile&run") - - cmd="cd ../mbnet && sed -i 's/#define TM_MDL_TYPE TM_MDL_FP32/#define TM_MDL_TYPE TM_MDL_INT8/g' ../../include/tm_port.h && rm -rf build && mkdir build && cd build && cmake .. && make && ./mbnet" - res = runcmd(cmd) + cmd="sed -i 's/#define TM_MDL_TYPE TM_MDL_FP32/#define TM_MDL_TYPE TM_MDL_INT8/g' ../../include/tm_port.h" + res = runcmd(cmd, cwd=mbnet_dir) + res = runcmd("rm -rf build && mkdir build && cd build && cmake .. && make && ./mbnet", cwd=mbnet_dir) print(res[-1]) - if res[-1] == "### Predict output is: Class 292 (tiger, Panthera tigris), Prob 0.824": - print("====Step2.2.2: OK~") - runcmd("rm ../../tools/tmdl/mbnet128_0.25_q.tmdl") #clean tmdl - else: - print("====Step2.2.2: ERR!!!") - exit(-2) + assert 'Class 292 (tiger, Panthera tigris), Prob 0.8' in res[-1] + + runcmd("rm ../../tools/tmdl/mbnet128_0.25_q.tmdl") #clean tmdl t1= time.time() print("========Step2.2: test MBNET int8 OK~ use %.1fs"%(t1-t0)) From aa34e7c08b97b9fd4b7ddb862648f53fd28dd7a0 Mon Sep 17 00:00:00 2001 From: Jon Nordby Date: Fri, 13 Dec 2024 22:56:03 +0100 Subject: [PATCH 8/9] mbnet: Fix wrong include auto_test for mbnet int8 was failing due to this --- examples/mbnet/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/mbnet/main.c b/examples/mbnet/main.c index 63cc385..4abf96e 100644 --- a/examples/mbnet/main.c +++ b/examples/mbnet/main.c @@ -25,7 +25,7 @@ limitations under the License. #elif TM_MDL_TYPE==TM_MDL_FP16 #include "../../tools/tmdl/mbnet128_0.25_fp16.h" #elif TM_MDL_TYPE==TM_MDL_INT8 - #include "../../tools/mbtestv2.h" + #include "../../tools/tmdl/mbnet128_0.25_q.h" #elif TM_MDL_TYPE==TM_MDL_FP8_143 #include "../../tools/tmdl/mbnet128_0.25_fp8_143.h" #elif TM_MDL_TYPE==TM_MDL_FP8_152 From 7936ab0ee8dfdc1ae9c6340eeb4a90508d7a01b4 Mon Sep 17 00:00:00 2001 From: Jon Nordby Date: Fri, 13 Dec 2024 23:30:19 +0100 Subject: [PATCH 9/9] README: Update how to run the tools --- README.md | 8 ++++---- README_ZH.md | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index dcb7ee8..234059b 100644 --- a/README.md +++ b/README.md @@ -220,17 +220,17 @@ And now just put them into your project, compile it~ ## How to train/convert models There are training scripts in examples/mnist to learn how to train simple mnist models. -> Note: you need install TensorFlow (>=2.7) first. +> Note: you need install TinyMaix first. After training and save h5 models, you can use scripts in tools to convert to tmdl or c header files. 1. h5_to_tflite.py convert h5 model to float or int8 quant tflite files - python3 h5_to_tflite.py h5/mnist.h5 tflite/mnist_f.tflite 0 - python3 h5_to_tflite.py h5/mnist.h5 tflite/mnist_q.tflite 1 quant_img_mnist/ 0to1 + python -m tinymaix.tools.h5_to_tflite h5/mnist.h5 tflite/mnist_f.tflite 0 + python -m tinymaix.tools.h5_to_tflite h5/mnist.h5 tflite/mnist_q.tflite 1 quant_img_mnist/ 0to1 2. tflite2tmdl.py convert tflite file to tmdl or c header files. - python3 tflite2tmdl.py tflite/mnist_q.tflite tmdl/mnist_q.tmdl int8 1 28,28,1 10 + python -m tinymaix.tools.tflite2tmdl tflite/mnist_q.tflite tmdl/mnist_q.tmdl int8 1 28,28,1 10 ``` ================ pack model head ================ mdl_type =0 diff --git a/README_ZH.md b/README_ZH.md index 7767f36..c5f26db 100644 --- a/README_ZH.md +++ b/README_ZH.md @@ -198,17 +198,17 @@ TinyMaix的核心文件只有这5个:tm_model.c, tm_layers.c, tinymaix.h, tm_p ## 怎样训练/转换模型 在examples/mnist下有训练脚本可以学习如何训练基础的mnist模型 -> 注意:你需要先安装TensorFlow (>=2.7) 环境. +> 注意:你需要先安装TinyMaix 环境. 完成训练并保存h5模型后,你可以使用以下脚本转换原始模型到tmdl或者c头文件。 1. h5_to_tflite.py 转换h5模型到浮点或者int8量化的tflite模型 - python3 h5_to_tflite.py h5/mnist.h5 tflite/mnist_f.tflite 0 - python3 h5_to_tflite.py h5/mnist.h5 tflite/mnist_q.tflite 1 quant_img_mnist/ 0to1 + python -m tinymaix.tools.h5_to_tflite h5/mnist.h5 tflite/mnist_f.tflite 0 + python -m tinymaix.tools.h5_to_tflite h5/mnist.h5 tflite/mnist_q.tflite 1 quant_img_mnist/ 0to1 2. tflite2tmdl.py 转换tflite文件到tmdl或者c头文件 - python3 tflite2tmdl.py tflite/mnist_q.tflite tmdl/mnist_q.tmdl int8 1 28,28,1 10 + python -m tinymaix.tools.tflite2tmdl tflite/mnist_q.tflite tmdl/mnist_q.tmdl int8 1 28,28,1 10 ``` ================ pack model head ================ mdl_type =0