Skip to content

Conversation

KiyoLelou10
Copy link

@KiyoLelou10 KiyoLelou10 commented Aug 18, 2025

Contribution description

This PR adds a new advanced example: examples/advanced/tflm_fmnist_demo, a minimal TensorFlow Lite Micro (TFLM) INT8 inference demo for RIOT.

Highlights:

  • Embedded INT8 model in model_data.cpp (g_model, g_model_len), distilled from a larger teacher model (see provenance below).

  • 48×48 grayscale Fashion-MNIST sample images are provided. At runtime the app quantizes these images into the model’s input tensor and prints the predicted class.

  • Self-contained example showing how to:

    • pull in tflite-micro via USEPKG
    • set up a MicroInterpreter, tensor arena, and minimal op resolver (Conv2D, DepthwiseConv2D, AvgPool, FullyConnected, Reshape, Mean, Quantize/Dequantize)
    • embed model bytes and small test inputs in firmware
  • Includes helper scripts and ten PNGs to regenerate the small test set, but the firmware itself only consumes samples.h (the PNGs are for developer convenience).

Provenance of the student model: https://github.com/KiyoLelou10/FashionMNISTDistill
A larger model was trained and distilled into this compact INT8 student. That repo also contains people images; with the same pattern shown here, one could train/distill a tiny model to count people in a photo (e.g., 0–5+) and run it on RIOT.

Directory (new):

examples/advanced/tflm_fmnist_demo/
├─ imgs/                     # 10 PNGs included (already used to build samples.h)
├─ main.cpp                  # RIOT app
├─ Makefile                  # uses C++ and pulls tflite-micro
├─ model_data.cpp            # embedded INT8 TFLite model (C array)
├─ samples.h                 # 10 images (uint8[48*48]) + labels used by firmware
├─ pngs_to_samples_h.py      # optional: rebuild samples.h from imgs/
└─ save_fmnist_10_pngs.py    # optional: re-generate 10 Fashion-MNIST PNGs

Testing procedure

nRF52840 DK

cd examples/advanced/tflm_fmnist_demo
PORT=/dev/ttyACM0 BOARD=nrf52840dk make all term flash WERROR=0

Notes:

  • The first build/flash takes a while because TFLM packages are compiled (flatbuffers, gemmlowp, ruy, kernels, micro, etc.). This is expected; you’ll see lines like:

    "make" -C .../tflite-micro/tensorflow/lite/kernels -f .../tflite-kernels.mk
    "make" -C .../tflite-micro/tensorflow/lite/kernels/internal -f .../tflite-kernels-internal.mk
    "make" -C .../tflite-micro/tensorflow/lite/micro -f .../tflite-micro.mk
    
  • Warnings from TFLM are noisy; WERROR=0 keeps them non-fatal.

  • If AllocateTensors() fails on another board, try a larger arena:

    TENSOR_ARENA_SIZE=131072 PORT=/dev/ttyACM0 BOARD=<your_board> make flash term WERROR=0
    

Expected serial output (example):

[#0] pred=Sneaker     (true=Sandal)      time=3148495 us
[#1] pred=Shirt       (true=Shirt)       time=3148515 us
[#2] pred=Shirt       (true=Coat)        time=3148498 us
[#3] pred=Trouser     (true=Trouser)     time=3148511 us
[#4] pred=Shirt       (true=Coat)        time=3148493 us
[#5] pred=Coat        (true=Coat)        time=3148493 us
[#6] pred=Ankle boot  (true=Ankle boot)  time=3148493 us
[#7] pred=Shirt       (true=Coat)        time=3148492 us
[#8] pred=Sneaker     (true=Bag)         time=3148505 us
[#9] pred=Ankle boot  (true=Ankle boot)  time=3148493 us

Done.

(With reference kernels on nRF52840, ~3.1s/inference is normal. Enable CMSIS-NN for faster.)

Native (Linux host)

BOARD=native make -j WERROR=0
make term BOARD=native

Regenerate the sample header (optional)

The firmware uses samples.h. PNGs in imgs/ are provided so reviewers can rebuild:

python3 pngs_to_samples_h.py --img-dir ./imgs --out-header samples.h --limit 10

(Or create new PNGs with save_fmnist_10_pngs.py and regenerate samples.h.)

Issues/PRs references

None. This is a self-contained new example.

@KiyoLelou10 KiyoLelou10 requested a review from jia200x as a code owner August 18, 2025 00:45
@github-actions github-actions bot added Area: doc Area: Documentation Area: examples Area: Example Applications labels Aug 18, 2025
@crasbe crasbe added Type: new feature The issue requests / The PR implemements a new feature for RIOT CI: ready for build If set, CI server will compile all applications for all available boards for the labeled PR labels Aug 18, 2025
@riot-ci
Copy link

riot-ci commented Aug 18, 2025

Murdock results

FAILED

9e22496 examples/advanced: add TFLM Fashion-MNIST INT8 demo (tflm_fmnist_demo)

Success Failures Total Runtime
5 1 13 03m:48s
Build failures (1)
Application Target Toolchain Runtime (s) Worker
examples/advanced/tflm_fmnist_demo esp32-wroom-32 gnu 15.01 tud-1

Artifacts

Copy link
Contributor

@crasbe crasbe left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did not go through the code very thorougly yet, but here are some styling related comments. Please also check the output of the static-tests in the "Files" tab of the Github PR section (https://github.com/RIOT-OS/RIOT/pull/21664/files) or run make static-test in your local repository.

There are a lot of trailing whitespaces at the end of code lines

USEPKG += tflite-micro
USEMODULE += xtimer

# ✅ List ALL C++ sources here
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
# List ALL C++ sources here
# List ALL C++ sources here

It's generally good practise not to use emojis in source files, even though with modern editors it's possible. Did ChatGPT generate this?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think so yes, since I had a bug and it gave me a new version of the Makefile, by the way, my work in RIOT was part of a mandatory internship I did for Mr. Hahm at my university which I finished 2 days ago, since I am starting to do my thesis now I do not have a lot of time, I will probably only after completing it, have time to update all of the mentioned aspects.
In the meantime you can gladly go through my code in more depth and point out other flaws if you want.
Thank you very much for your review thus far, I do not know how high the demand is, but I saw that this tf light micro library was available in RIOT, so I thought it would be good to make an advanced example out of this


FEATURES_REQUIRED += cpp
USEPKG += tflite-micro
USEMODULE += xtimer
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

xtimer has been deprecated for a long time, it would be good to use ztimer instead.

for (int i = 0; i < SAMPLE_COUNT; ++i) {
quantize_into_input(&interpreter, g_images[i]);

uint32_t t0 = xtimer_now_usec();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you really need microsecond precision? On embedded system, that can be quite power consuming.

@@ -0,0 +1,123 @@
// main.cpp — RIOT + TFLite Micro, runtime quantization from uint8 images (48x48)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add a header to your source files according to our Coding Convention: https://github.com/RIOT-OS/RIOT/blob/master/CODING_CONVENTIONS.md#documentation

#include "xtimer.h"
#include "samples.h" // generated by the Python helper: g_images (uint8), g_labels

// TFLite Micro
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

RIOT uses C-Style Comments instead of C++ Style comments, please adapt the source files according to our Coding Convention: https://github.com/RIOT-OS/RIOT/blob/master/CODING_CONVENTIONS.md#comments


// Adjust at build time: make TENSOR_ARENA_SIZE=262144
#ifndef TENSOR_ARENA_SIZE
#define TENSOR_ARENA_SIZE (200 * 1024)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
#define TENSOR_ARENA_SIZE (200 * 1024)
# define TENSOR_ARENA_SIZE (200 * 1024)

Preprocessor directives inside of #ifs should be indended, please refer to our Coding Convention: https://github.com/RIOT-OS/RIOT/blob/master/CODING_CONVENTIONS.md#indentation-of-preprocessor-directives

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Area: doc Area: Documentation Area: examples Area: Example Applications CI: ready for build If set, CI server will compile all applications for all available boards for the labeled PR Type: new feature The issue requests / The PR implemements a new feature for RIOT
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants