Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 25 additions & 25 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -10,49 +10,49 @@ MPY_DIR_ABS = $(abspath $(MPY_DIR))

MODULES_PATH = ./dist/$(ARCH)_$(MPY_ABI_VERSION)

$(MODULES_PATH)/emltrees.mpy:
make -C src/emltrees/ ARCH=$(ARCH) MPY_DIR=$(MPY_DIR_ABS) V=1 clean dist
$(MODULES_PATH)/emlearn_trees.mpy:
make -C src/emlearn_trees/ ARCH=$(ARCH) MPY_DIR=$(MPY_DIR_ABS) V=1 clean dist

$(MODULES_PATH)/emlneighbors.mpy:
make -C src/emlneighbors/ ARCH=$(ARCH) MPY_DIR=$(MPY_DIR_ABS) V=1 clean dist
$(MODULES_PATH)/emlearn_neighbors.mpy:
make -C src/emlearn_neighbors/ ARCH=$(ARCH) MPY_DIR=$(MPY_DIR_ABS) V=1 clean dist

$(MODULES_PATH)/emliir.mpy:
make -C src/emliir/ ARCH=$(ARCH) MPY_DIR=$(MPY_DIR_ABS) V=1 clean dist
$(MODULES_PATH)/emlearn_iir.mpy:
make -C src/emlearn_iir/ ARCH=$(ARCH) MPY_DIR=$(MPY_DIR_ABS) V=1 clean dist

$(MODULES_PATH)/emlfft.mpy:
make -C src/emlfft/ ARCH=$(ARCH) MPY_DIR=$(MPY_DIR_ABS) V=1 clean dist
$(MODULES_PATH)/emlearn_fft.mpy:
make -C src/emlearn_fft/ ARCH=$(ARCH) MPY_DIR=$(MPY_DIR_ABS) V=1 clean dist

$(MODULES_PATH)/tinymaix_cnn.mpy:
$(MODULES_PATH)/emlearn_cnn.mpy:
make -C src/tinymaix_cnn/ ARCH=$(ARCH) MPY_DIR=$(MPY_DIR_ABS) V=1 clean dist

$(MODULES_PATH)/emlkmeans.mpy:
make -C src/emlkmeans/ ARCH=$(ARCH) MPY_DIR=$(MPY_DIR_ABS) V=1 clean dist
$(MODULES_PATH)/emlearn_kmeans.mpy:
make -C src/emlearn_kmeans/ ARCH=$(ARCH) MPY_DIR=$(MPY_DIR_ABS) V=1 clean dist

$(MODULES_PATH)/eml_iir_q15.mpy:
make -C src/eml_iir_q15/ ARCH=$(ARCH) MPY_DIR=$(MPY_DIR_ABS) V=1 clean dist
$(MODULES_PATH)/emlearn_iir_q15.mpy:
make -C src/emlearn_iir_q15/ ARCH=$(ARCH) MPY_DIR=$(MPY_DIR_ABS) V=1 clean dist

$(MODULES_PATH)/emlearn_arrayutils.mpy:
make -C src/emlearn_arrayutils/ ARCH=$(ARCH) MPY_DIR=$(MPY_DIR_ABS) V=1 clean dist

emltrees.results: $(MODULES_PATH)/emltrees.mpy
emlearn_trees.results: $(MODULES_PATH)/emlearn_trees.mpy
MICROPYPATH=$(MODULES_PATH) $(MICROPYTHON_BIN) tests/test_trees.py

emlneighbors.results: $(MODULES_PATH)/emlneighbors.mpy
emlearn_neighbors.results: $(MODULES_PATH)/emlearn_neighbors.mpy
MICROPYPATH=$(MODULES_PATH) $(MICROPYTHON_BIN) tests/test_neighbors.py

emliir.results: $(MODULES_PATH)/emliir.mpy
emlearn_iir.results: $(MODULES_PATH)/emlearn_iir.mpy
MICROPYPATH=$(MODULES_PATH) $(MICROPYTHON_BIN) tests/test_iir.py

emlfft.results: $(MODULES_PATH)/emlfft.mpy
emlearn_fft.results: $(MODULES_PATH)/emlearn_fft.mpy
MICROPYPATH=$(MODULES_PATH) $(MICROPYTHON_BIN) tests/test_fft.py

tinymaix_cnn.results: $(MODULES_PATH)/tinymaix_cnn.mpy
emlearn_cnn.results: $(MODULES_PATH)/emlearn_cnn.mpy
MICROPYPATH=$(MODULES_PATH) $(MICROPYTHON_BIN) tests/test_cnn.py

emlkmeans.results: $(MODULES_PATH)/emlkmeans.mpy
emlearn_kmeans.results: $(MODULES_PATH)/emlearn_kmeans.mpy
MICROPYPATH=$(MODULES_PATH) $(MICROPYTHON_BIN) tests/test_kmeans.py

eml_iir_q15.results: $(MODULES_PATH)/eml_iir_q15.mpy
emlearn_iir_q15.results: $(MODULES_PATH)/emlearn_iir_q15.mpy
MICROPYPATH=$(MODULES_PATH) $(MICROPYTHON_BIN) tests/test_iir_q15.py

emlearn_arrayutils.results: $(MODULES_PATH)/emlearn_arrayutils.mpy
Expand All @@ -61,9 +61,9 @@ emlearn_arrayutils.results: $(MODULES_PATH)/emlearn_arrayutils.mpy
.PHONY: clean

clean:
make -C src/emltrees/ ARCH=$(ARCH) MPY_DIR=$(MPY_DIR_ABS) V=1 clean
make -C src/emlneighbors/ ARCH=$(ARCH) MPY_DIR=$(MPY_DIR_ABS) V=1 clean
make -C src/emliir/ ARCH=$(ARCH) MPY_DIR=$(MPY_DIR_ABS) V=1 clean
make -C src/emlearn_trees/ ARCH=$(ARCH) MPY_DIR=$(MPY_DIR_ABS) V=1 clean
make -C src/emlearn_neighbors/ ARCH=$(ARCH) MPY_DIR=$(MPY_DIR_ABS) V=1 clean
make -C src/emlearn_iir/ ARCH=$(ARCH) MPY_DIR=$(MPY_DIR_ABS) V=1 clean
rm -rf ./dist

RELEASE_NAME = emlearn-micropython-$(VERSION)
Expand All @@ -74,8 +74,8 @@ release:
zip -r $(RELEASE_NAME).zip $(RELEASE_NAME)
#cp $(RELEASE_NAME).zip emlearn-micropython-latest.zip

check: emltrees.results emlneighbors.results emliir.results eml_iir_q15.results emlfft.results emlkmeans.results emlearn_arrayutils.results tinymaix_cnn.results
check: emlearn_trees.results emlearn_neighbors.results emlearn_iir.results emlearn_iir_q15.results emlearn_fft.results emlearn_kmeans.results emlearn_arrayutils.results emlearn_cnn.results

dist: $(MODULES_PATH)/emltrees.mpy $(MODULES_PATH)/emlneighbors.mpy $(MODULES_PATH)/emliir.mpy $(MODULES_PATH)/eml_iir_q15.mpy $(MODULES_PATH)/emlfft.mpy $(MODULES_PATH)/emlkmeans.mpy $(MODULES_PATH)/emlearn_arrayutils.mpy $(MODULES_PATH)/tinymaix_cnn.mpy
dist: $(MODULES_PATH)/emlearn_trees.mpy $(MODULES_PATH)/emlearn_neighbors.mpy $(MODULES_PATH)/emlearn_iir.mpy $(MODULES_PATH)/emlearn_iir_q15.mpy $(MODULES_PATH)/emlearn_fft.mpy $(MODULES_PATH)/emlearn_kmeans.mpy $(MODULES_PATH)/emlearn_arrayutils.mpy $(MODULES_PATH)/emlearn_cnn.mpy


52 changes: 13 additions & 39 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,10 +57,21 @@ Download the repository with examples etc
git clone https://github.com/emlearn/emlearn-micropython
```

## Installing from a release
## Usage

Start with the instructions in [XOR example](./examples/xor_trees/).


#### Find architecture and .mpy version

The correct .mpy files to use depend on the CPU architecture of your microcontroller,
as well as the MicroPython version.

| MicroPython version | .mpy version |
|---------------------| ------------- |
| 1.23.x | 6.3 |


Identify which CPU architecture your device uses.
You need to specify `ARCH` to install the correct module version.

Expand All @@ -79,43 +90,6 @@ Information is also available in the official documentation:
[MicroPython: .mpy files](https://docs.micropython.org/en/latest/reference/mpyfiles.html#versioning-and-compatibility-of-mpy-files)


#### Download release files

Download from [releases](https://github.com/emlearn/emlearn-micropython/releases).

#### Install on device

Copy the .mpy file for the correct `ARCH` to your device.
```
mpremote cp emltrees.mpy :emltrees.mpy
mpremote cp emlneighbors.mpy :emlneighbors.mpy
```

NOTE: If there is no ready-made build for your device/architecture,
then you will need to build the .mpy module yourself.

## Usage

NOTE: Make sure to install the module first (see above)

Train a model with scikit-learn
```
pip install emlearn scikit-learn
python examples/xor_trees/xor_train.py
```

Copy model file to device

```
mpremote cp xor_model.csv :xor_model.csv
```

Run program that uses the model

```
mpremote run examples/xor_run.py
```

## Benchmarks

#### UCI handwriting digits
Expand Down Expand Up @@ -157,7 +131,7 @@ make dist ARCH=armv6m MPY_DIR=../micropython

Install it on device
```
mpremote cp dist/armv6m*/emltrees.mpy :emltrees.mpy
mpremote cp dist/armv6m*/emlearn_trees.mpy :emlearn_trees.mpy
```

#### Run tests
Expand Down
6 changes: 3 additions & 3 deletions benchmarks/digits_trees/digits_run.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,15 @@

from everywhere_digits import RandomForestClassifier
import m2c_digits
import emltrees
import emlearn_trees


def emlearn_create():
model = emltrees.new(10, 1000, 10)
model = emlearn_trees.new(10, 1000, 10)

# Load a CSV file with the model
with open('eml_digits.csv', 'r') as f:
emltrees.load_model(model, f)
emlearn_trees.load_model(model, f)
return model

def argmax(l):
Expand Down
10 changes: 5 additions & 5 deletions benchmarks/fft/fft_benchmark.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@
except ImportError as e:
print(e)

emlfft = None
emlearn_fft = None
try:
import emlfft
import emlearn_fft
pass
except ImportError as e:
print(e)
Expand Down Expand Up @@ -65,13 +65,13 @@ def run_one(real, imag, n, repeat=10):
d = ((time.ticks_diff(time.ticks_us(), start)) / repeat) / 1000.0 # ms
print('ulab', n, d)

# FIXME: this causes MicroPython to crash inside emlfft on ESP32
# FIXME: this causes MicroPython to crash inside emlearn_fft on ESP32
#gc.collect()

# emlearn
if emlearn:
fft2 = emlfft.FFT(n)
emlfft.fill(fft2, n)
fft2 = emlearn_fft.FFT(n)
emlearn_fft.fill(fft2, n)
gc.collect()

start = time.ticks_us()
Expand Down
4 changes: 2 additions & 2 deletions benchmarks/fft/fft_benchmark.sh
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
# NOTE: MicroPython must be flashed before-hand
# and emlfft.mpy built
# and emlearn_fft.mpy built

MPREMOTE='mpremote'

${MPREMOTE} cp src/emlfft/emlfft.mpy :
${MPREMOTE} cp src/emlearn_fft/emlearn_fft.mpy :
${MPREMOTE} cp benchmarks/fft/fft_python.py :

${MPREMOTE} run benchmarks/fft/fft_benchmark.py
Expand Down
8 changes: 4 additions & 4 deletions benchmarks/iir/iir_benchmark.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@
print(e)
pass

emliir = None
emlearn_iir = None
try:
import emliir
import emlearn_iir
except ImportError as e:
print(e)
pass
Expand Down Expand Up @@ -70,9 +70,9 @@ def main():
print('ulab', t)

# emlearn
if emliir:
if emlearn_iir:
start = time.ticks_us()
iir = emliir.new(coeff)
iir = emlearn_iir.new(coeff)
for r in range(repeats):
iir.run(a)
t = (time.ticks_diff(time.ticks_us(), start) / repeats ) / 1000.0 # ms
Expand Down
8 changes: 4 additions & 4 deletions benchmarks/iir/iir_run.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,11 @@ def iir_process_file(inp, out, filters, chunksize):
if len(reader.shape) != 1:
raise ValueError("Input must be 1d")
if reader.typecode == 'f':
import emliir
filter = emliir.new(coefficients)
import emlearn_iir
filter = emlearn_iir.new(coefficients)
elif reader.typecode == 'h':
import eml_iir_q15
filter = eml_iir_q15.new(coefficients)
import emlearn_iir_q15
filter = emlearn_iir_q15.new(coefficients)
else:
raise ValueError("Input must either be float32/f or int16/h")

Expand Down
29 changes: 10 additions & 19 deletions doc/TODO.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
# User journey

- Level 0a. Run a pretrained example/demo in the browser
- Level 0b. Run a pretrained example/demo on a board
- Level 0b. Run a pretrained example/demo on PC/host
- Level 0c. Run a pretrained example/demo on a board
- Level 1. Train custom model on-device
- Level 2. Collect a dataset, do training on PC, deploy back to microcontroller
- Level 3. Bake the custom model into the firmware
Expand All @@ -20,33 +21,21 @@

sequence. On-device training demo

- Record piezo data with ADC. 100 Hz?
Typical taps. Slower pushes. Handling noises.
- Setup event detection for piezo.
In its own module.
Threshold on delta and level?
- Create emliir module, use for piezo detection
- Use accelerometer instead of piezo. On M5StickC, for example
- Compute impulsive-ness feature. Magnitude, RMS, exponential smooth, then Delta * times level ?
- Alternative: Use IIR for knock detection
- Maybe blink during unlocked state
- Add a blink to each event. For user feedback
- Make demo video
- Add some documentation / README
- Make state diagram
- Make timing diagram. Highlight distances/features
- Add some documentation / README

Learnings.

- Putting piezo on small thin plate worked well.
On table not working, no response.
Hitting direct not so good either, rise of finger causes change. Double-trigger. Also tricky to hit in right place.
- LEDs as protection diodes worked well. Both red and green can be used. Lights up on direct hits, if placed by piezo.
- Analog RC filter is beneficial for piezo connections. Using 10k+100nF, has 160 Hz cutoff. Should maybe move it to 80Hz? Since only sampling at 100 Hz.
- Only direct hits can reach trigger levels on 3.3V I/O. Need ADC for other cases. But am seing some 100mV when placed on small plate

Examples
#### Examples

- Add a novelty detection example?

Benchmarks
#### Benchmarks

- Add FLASH and RAM usage
- Test gzip compression of .csv model for trees
Expand All @@ -56,3 +45,5 @@ Benchmarks
In-browser demo

- Test MicroPython build for WASM/browser
- Test getting audio input into MicroPython Webassembly
- Test getting IMU data (ie on phone), in browser
6 changes: 3 additions & 3 deletions doc/micropython-tinyml-status.md
Original file line number Diff line number Diff line change
Expand Up @@ -167,14 +167,14 @@ FIR filters.

IIR filters.
`scipy.signal.sosfilt` available in [ulab](https://github.com/v923z/micropython-ulab).
`emliir` available in [emlearn-micropython](https://github.com/emlearn/emlearn-micropython).
`emlearn_iir` available in [emlearn-micropython](https://github.com/emlearn/emlearn-micropython).

### Fast Fourier Transform (FFT)
Key part of computing frequency spectrum, or time-frequency representations (spectrogram).

FFT.
`numpy.fft.fft` available in [ulab](https://github.com/v923z/micropython-ulab).
`emlfft` available in [emlearn-micropython](https://github.com/emlearn/emlearn-micropython).
`emlearn_fft` available in [emlearn-micropython](https://github.com/emlearn/emlearn-micropython).

DCT.
Not available?
Expand All @@ -195,7 +195,7 @@ But over 10x slower than emlearn-micropython.

### K-nearest-neighbours

`emlneighbors` available in [emlearn-micropython](https://github.com/emlearn/emlearn-micropython).
`emlearn_neighbors` available in [emlearn-micropython](https://github.com/emlearn/emlearn-micropython).

### Convolutional Neural Network

Expand Down
6 changes: 3 additions & 3 deletions examples/color_quantize_kmeans/color_quantize.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
import os
import gc

import emlkmeans
import emlearn_kmeans

@micropython.native
def quantize_image(img, quant, palette, rowstride):
Expand Down Expand Up @@ -55,7 +55,7 @@ def quantize_image_inner(img, quant, palette, rowstride : int, rows : int):
#rgb = img[i:i+3]

# find closest value in palette
palette_idx, distance = emlkmeans.euclidean_argmin(palette, rgb)
palette_idx, distance = emlearn_kmeans.euclidean_argmin(palette, rgb)
#palette_idx, distance = 0, 0

o = row_offset + col
Expand Down Expand Up @@ -103,7 +103,7 @@ def quantize_path(inp, outp, palette, n_samples=100):

# Learn a palette
start = time.ticks_us()
emlkmeans.cluster(samples, palette, features=3, max_iter=20)
emlearn_kmeans.cluster(samples, palette, features=3, max_iter=20)
dur = (time.ticks_diff(time.ticks_us(), start) / 1000.0)
print('cluster duration (ms)', dur)

Expand Down
Loading
Loading