Level up your TinyML skills

Eloquent Edge Impulse for Arduino

An Arduino library to make Edge Impulse Neural Networks easy to use

Eloquent Edge Impulse for Arduino


Edge Impulse is a great tool to develop TinyML models without coding and in a simple to use environment.

Sadly, integrating those models back into your Arduino project is not that easy as it could be.

Thanks to the Eloquent Arduino library, though, things have changed!

Before continuing, please install the EloquentArduino library version 2.1.3 or above in the Arduino IDE. Install EloquentArduino library version 2.1.3 in Arduino IDE

How to use

Using the Eloquent library to run Edge Impulse models is pretty easy.

First of all, create your model and export as an Arduino library.

Export Edge Impulse model as Arduino library
Export Edge Impulse model as Arduino library

Now, create a new Arduino sketch with the following code.

 /**
 * This example shows how to use the Eloquent library
 * to perform inference using the EdgeImpulse generated library
 */
#include <replace_with_edge_impulse_inferencing.h>
#include <eloquent.h>
#include <eloquent/tinyml/edgeimpulse.h>


Eloquent::TinyML::EdgeImpulse::Impulse impulse;


void setup() {
    Serial.begin(115200);
    delay(3000);
    Serial.println("Starting EdgeImpulse inference");
    Serial.println("Paste your feature vector in the Serial Monitor and get the predicted value");
    Serial.print("(expecting ");
    Serial.print(EI_CLASSIFIER_DSP_INPUT_FRAME_SIZE);
    Serial.println(" comma-separated features)");
}


void loop() {
    float features[EI_CLASSIFIER_DSP_INPUT_FRAME_SIZE] = {0};

    if (!Serial.available())
        return;

    for (int i = 0; i < EI_CLASSIFIER_DSP_INPUT_FRAME_SIZE; i++)
        features[i] = Serial.readStringUntil(',').toFloat();

    // here is where the magic happens...
    Serial.print("Predicted class: ");
    Serial.println(impulse.predict(features));
    Serial.print("Predicted label: ");
    Serial.println(impulse.getLabel());

    // debug class probabilities and timing
    impulse.printTo(Serial);
}
 

Hopefully the code is self-explanatory:

  • it loads the library you exported from Edge Impulse
  • it loads the Eloquent Edge Impulse library
  • it instantiates an impulse object

When the user sends a feature vector to the Serial Monitor, the impulse performs the inference and prints the results back to the Serial Monitor.

Done!

Looks pretty clean, right?

Compare with the example generated from Edge Impulse.


/**
 * @brief    Arduino main function
 */
void loop()
{
    ei_printf("Edge Impulse standalone inferencing (Arduino)\n");

    if (sizeof(features) / sizeof(float) != EI_CLASSIFIER_DSP_INPUT_FRAME_SIZE) {
        ei_printf("The size of your 'features' array is not correct. Expected %lu items, but had %lu\n",
        EI_CLASSIFIER_DSP_INPUT_FRAME_SIZE, sizeof(features) / sizeof(float));
        delay(1000);
        return;
    }

    ei_impulse_result_t result = { 0 };

    // the features are stored into flash, and we don't want to load everything into RAM
    signal_t features_signal;
    features_signal.total_length = sizeof(features) / sizeof(features[0]);
    features_signal.get_data = &raw_feature_get_data;

    // invoke the impulse
    EI_IMPULSE_ERROR res = run_classifier(&features_signal, &result, false /* debug */);
    ei_printf("run_classifier returned: %d\n", res);

    if (res != 0) return;

    // print the predictions
    ei_printf("Predictions ");
    ei_printf("(DSP: %d ms., Classification: %d ms., Anomaly: %d ms.)",
    result.timing.dsp, result.timing.classification, result.timing.anomaly);
    ei_printf(": \n");
    ei_printf("[");
    for (size_t ix = 0; ix < EI_CLASSIFIER_LABEL_COUNT; ix++) {
        ei_printf("%.5f", result.classification[ix].value);
        #if EI_CLASSIFIER_HAS_ANOMALY == 1
            ei_printf(", ");
        #else
            if (ix != EI_CLASSIFIER_LABEL_COUNT - 1) {
                ei_printf(", ");
            }
        #endif
    }
    #if EI_CLASSIFIER_HAS_ANOMALY == 1
    ei_printf("%.3f", result.anomaly);
    #endif
    ei_printf("]\n");

    // human-readable predictions
    for (size_t ix = 0; ix < EI_CLASSIFIER_LABEL_COUNT; ix++) {
        ei_printf("    %s: %.5f\n", result.classification[ix].label, result.classification[ix].value);
    }
    #if EI_CLASSIFIER_HAS_ANOMALY == 1
    ei_printf("    anomaly score: %.3f\n", result.anomaly);
    #endif

    delay(1000);
}
            

I think we have a clear winner here.

Available methods

Here's the complete list of the methods that you can call on the impulse object.

int8_t predict(float *features)
        Perform inference on the given feature vector.
            Returns the most probable class index, or -1 on error.
    
String predictLabel(float *features)
        Perform inference on the given feature vector.
            Returns the most probable class name.
    
String getLabel(void)
        Get label of latest prediction.
    
float getProba(void)
        Get probability of latest prediction.
    
uint16_t getDspTiming(void)
        Get time spent on DSP, in milliseconds.
    
uint16_t getClassificationTiming(void)
        Get time spent on classification, in milliseconds.
    
uint16_t getAnomalyTiming(void)
        Get time spent on anomaly detection, in milliseconds, if anomaly detection was turned on during model generation.
    
bool isAnomaly(void)
        Return true when an anomaly is detected, if anomaly detection was turned on during model generation.
    
void setMaxAnomalyScore(float maxScore)
        Set the max score after which a prediction is considered an anomaly.
    
void printTo(PrinterInterface &printer)
        Print debug information to given printer template class.
            Many times you will pass the Serial object.
    

Monthly Newsletter

Get post previews and exclusive tutorials in your inbox

We use Mailchimp as our marketing platform. By submitting this form, you acknowledge that the information you provided will be transferred to Mailchimp for processing in accordance with their terms of use. We will use your email to send you updates relevant to this website.

Having troubles? Ask a question

Need a one to one call? Book now!

© Copyright 2022 Eloquent Arduino. All Rights Reserved.