A lot of forum threads ask about the possibility to run Machine learning on Arduino.
The answers mostly follow in one of these 3 categories:

  1. Arduino is too resource-constrained to handle Machine learning
  2. Come up with a naive implementation of a Multi Layer Perceptron
  3. (recently) Sure! You can use Tensorflow Lite for Microcontrollers

No single answer I read talked about the other 100s alghoritms that fall under the Machine learning umbrella. No. Single. One. Let me explain what I think is wrong with this.

First of all I'd like to state one absolutely important thing:

Artificial intelligence ≠ Machine learning ≠ Neural networks. This should be clear Click To Tweet

I admit most of those questions seemed to come from principiants. Also the answers, though, most often lack any sound knowledge about the topic.

You can run classification and regression on Arduino boards, even the less powerful ones: just don't use Neural networks. It's that simple. Click To Tweet

Introducing MicroML generator

So I do you actually run machine learning on such constrained devices?

Here you are: MicroML is a project to bring Machine learning algorithms to microcontrollers. It was born as an alternative to Tensorflow for Microcontrollers, which is solely dedicated to Artificial Neural Networks: here you will find leaner alternatives to neural networks to run inference even on 8-bit microcontrollers.

Quoting from the Tensoflow blog: The core runtime fits in 16 KB on an Arm Cortex M3 (that's just the runtime, without any actual operator!).

MicroML lets you deploy models that fit in under 2 Kb of RAM #microml #arduino #ai #ml Click To Tweet

At the current state, it can convert Support Vector Machines to optimized C code you can deploy on any MCU of you choice: Arduino (Uno, Nano, Micro...), ESP8266, ESP32 and really any other MCU with C support.

At the moment you can't deploy to Attiny boards because their compiler seems not to support variadic functions: I'll fix this as soon as possible, already got a working implementation

Why Support Vector Machines? Because they're really good at classifying highly-dimensional features and are quite easy to optimize for RAM-constrained environments (check the tutorial on Gesture identification which has 90 features!)

How to port a classifier

First of all, you need to train a classifier. You have to use the Python's library scikit-learn — which you're probably already using considering its widespread adoption. Then you need to install the MicroML package.

pip install micromlgen

Finally, you port your trained classifier to optimized C code.

from micromlgen import port
from sklearn.svm import SVC
from sklearn.datasets import load_iris

if __name__ == '__main__':
    iris = load_iris()
    X = iris.data
    y = iris.target
    clf = SVC(kernel='linear', gamma=0.001).fit(X, y)
    print(port(clf))

That's it: you now have all you need to do classification in your Arduino projects.

You MUST set gamma to a given value. The default auto will generate an error

Existing alternatives

There exists some alternatives to this library, but they suffer from some limitations:

  1. sklearn-porter can output C code (among the others), but it's not optimized for microcontrollers. You'll hit a wall on RAM because it needs to declare all the support vectors in memory (to have an idea, the breast cancer dataset produces a 57x30 matrix of doubles, totalling 6840 bytes just for the support vectors).
  2. emlearn is optimized for microcontrollers, can do Decision Tree, Random Forest, Naive Gaussian Bayes, Fully connected Neural Networks. No SVM though.

My effort was to find an implementation that needed the least amount possible of memory: this was possible sacrificing the program space, but that's less often a problem since RAM is usually the most limiting factor. If your model fills up the program space you can revert to sklearn-porter (if you have enough RAM, of course).

Use in Arduino project

There are two methods you will need to call to run the predictions in your project:

  1. predict(double features[]): it runs the actual prediction and returns a number representing the predicted class
  2. classIdxToName(uint8_t classIdx): converts the class index to a readable string, based on the classmap generated from your files
#include "model.h"

void classify() {
    Serial.print("Predicted class: ");
    Serial.println(classIdxToName(predict(features)));
}

I'm starting a series of tutorials about hands-on projects to put Machine learning in use: you can follow the Related posts links to follow along, so keep reading!

Help the blow grow