Skip to content

Support usage as external C modules #18

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
jonnor opened this issue Oct 18, 2024 · 15 comments
Closed

Support usage as external C modules #18

jonnor opened this issue Oct 18, 2024 · 15 comments
Labels
enhancement New feature or request

Comments

@jonnor
Copy link
Contributor

jonnor commented Oct 18, 2024

Right now emlearn is distributed as dynamic native modules. This is excellent for getting started, as one can just drop in a .mpy file on a standard MicroPython build and have things working. However, native modules always execute out of RAM, which tends to be more limited than FLASH space. In addition, for dynamic modules, some library code like for softfloat etc must be duplicated.
Additionally, the tooling for including .mpy files automatically in a firmware image is a bit missing right now.

For these reasons, it would be nice to optionally be able to include the modules, as "external C modules" during a MicroPython build.

@jonnor
Copy link
Contributor Author

jonnor commented Oct 18, 2024

There was a proof of concept of this done here, #2
However, it needs to be revisited, as many things have changed since then.

Right now there are some natmod hacks in the module code. So that should be fixed first, to reduce the amount of #ifdefs we need to support both ways of building. Via something like #15

@jonnor jonnor added the enhancement New feature or request label Oct 18, 2024
@jonnor
Copy link
Contributor Author

jonnor commented Oct 18, 2024

This might also enable to include in ports that only/primarily support external C modules, like "embed" and "webassembly".

@jonnor
Copy link
Contributor Author

jonnor commented Oct 21, 2024

This might help with #3 also

@bhcuong2008
Copy link

I tried to integrate emlearn .mpy frozen code to the build of MicroPython but failed. I hope the project would support build as user C modules. Also, it could utilize ESP-DSP, ESP-NN for specific ESP32 case.

micropython/micropython#17034

@jonnor
Copy link
Contributor Author

jonnor commented Apr 15, 2025

The .mpy files are intended to be installed into the filesystem using mip. Typically at runtime. But for including in a firmware image, I think there are some tools to pre-fill a filesystem. The ROMFS that just landed in MicroPython 1.25 might be one option.

@jonnor
Copy link
Contributor Author

jonnor commented Apr 16, 2025

Initial test was merged in #36 . There are some code difference needed between native modules and external C modules, but that looks manageable. Things that need to be figured out:

  • How to get the Python code included. Probably using the FROZEN_MANIFEST
  • How to run tests either against a build with external modules built-in, or against a stock build with .mpy files (at least for Unix)

Then we need to do a bit of testing, and also set everything up in CI. And of course add documentation once everything is working.

@jonnor
Copy link
Contributor Author

jonnor commented Apr 21, 2025

I managed to solve the above. The fact that everything needs to be done twice, for cmake and makefile-based ports, is super annoying and quite time-consuming.
But we now have basic support for this, including initial documentation at https://emlearn-micropython.readthedocs.io/en/latest/external_modules.html

@jonnor jonnor closed this as completed Apr 21, 2025
@bhcuong2008
Copy link

@jonnor, thank u so much. I will try to build it as USER_C_MODULES as soon as possible. I'd like cmake-based because ESP-IDF 5.x switching to CMake.

@bhcuong2008
Copy link

@jonnor, it's great that I can build it successfully on ESP32-C3, ESP32-C6. During the build, it needs to include some files from emlearn project, https://github.com/emlearn/emlearn/tree/master/emlearn, such as
eml_iir.h,
eml_trees.h,..

Then I must git clone it inside the folder dependencies, emlearn-micropython/dependencies/ and add it to include path to build USER_C_MODULES.

At some point during build process, it reports like below. Anyway, it is successful.

Traceback (most recent call last):
  File "<string>", line 1, in <module>
ModuleNotFoundError: No module named 'emlearn'
Traceback (most recent call last):
  File "<string>", line 1, in <module>
ModuleNotFoundError: No module named 'emlearn'
Traceback (most recent call last):
  File "<string>", line 1, in <module>
ModuleNotFoundError: No module named 'emlearn'
Traceback (most recent call last):
  File "<string>", line 1, in <module>
ModuleNotFoundError: No module named 'emlearn'
Traceback (most recent call last):
  File "<string>", line 1, in <module>
ModuleNotFoundError: No module named 'emlearn'

Then I run the example code here, https://github.com/emlearn/emlearn-micropython/tree/master/examples/xor_trees. It got successful result. I dont know whether it is expect result or not.

array('h', [0, 0]) 0
array('h', [32767, 32767]) 0
array('h', [0, 32767]) 1
array('h', [32767, 0]) 1

My custom build on ESP32-C3 now has emlearn, but redundant emlearn_fft_c, emlearn_trees_c modules. And lacking of emlearn_iir_q15, emlearn_kmeans, emlearn_neighbors. I will investigate it more.
Anyway, it's really great to have emlearn on my micropython build. Thank you again.

>>> help('modules')
__main__          builtins          errno             re
_asyncio          cmath             framebuf          select
_cinit            collections       gc                struct
_thread           cryptolib         hashlib           sys
array             deflate           heapq             time
asyncio/__init__  device            io                typing
asyncio/core      emlearn_arrayutils                  json              typing_extensions
asyncio/event     emlearn_cnn_int8  lvgl              uctypes
asyncio/funcs     emlearn_fft       math              ulab
asyncio/lock      emlearn_fft_c     micropython       vfs
asyncio/stream    emlearn_iir       os
binascii          emlearn_trees     platform
btree             emlearn_trees_c   random
Plus any modules on the filesystem
>>> 

@bhcuong2008
Copy link

I found emlearn_fft_c, emlearn_trees_c not redundant, it defined in the source. Besides, emlearn_iir_q15, emlearn_kmeans, emlearn_neighbors not included in cmake file, so it does not build. These folders dont have cmake file yet.

@jonnor
Copy link
Contributor Author

jonnor commented Apr 25, 2025

Yes, the _c modules are the underlying C modules. And then the modules without _c is a Python module, which also includes the stuff from the C module. This is what one needs to do with external modules to merge Python and C code into one module :) (dynamic native modules have built in support for this concept at runtime).

@jonnor
Copy link
Contributor Author

jonnor commented Apr 25, 2025

Thanks a lot for testing. Glad you got it to work :) The XOR output is correct.

Regarding ModuleNotFoundError: No module named 'emlearn' - this is because we expect to find the emlearn C library as a Python package. So the recommended fix is to install it with pip install emlearn. I forgot to add that to the documentation, will do that :)

Note that esp-idf can be a bit annoying here, as it has its own virtual environment for Python packages - so one needs to install the pages inside that virtual env.

@jonnor
Copy link
Contributor Author

jonnor commented Apr 25, 2025

PS: I have not tested yet myself on RISC-V ESP32 chips. I will test that soon I hope, and comment in #35 how it goes

@bhcuong2008
Copy link

Thanks a lot for testing. Glad you got it to work :) The XOR output is correct.

Regarding ModuleNotFoundError: No module named 'emlearn' - this is because we expect to find the emlearn C library as a Python package. So the recommended fix is to install it with pip install emlearn. I forgot to add that to the documentation, will do that :)

Note that esp-idf can be a bit annoying here, as it has its own virtual environment for Python packages - so one needs to install the pages inside that virtual env.

If lacking of this, as in my case, is the library still working properly?

@bhcuong2008
Copy link

I found emlearn_fft_c, emlearn_trees_c not redundant, it defined in the source. Besides, emlearn_iir_q15, emlearn_kmeans, emlearn_neighbors not included in cmake file, so it does not build. These folders dont have cmake file yet.

If possible, please add support c modules for emlearn_iir_q15, emlearn_kmeans, emlearn_neighbors.
Thank you so much again.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

2 participants