Run_classifier return -6

Question/Issue:

I’m experiencing an issue when deploying two Edge Impulse models using the Multi-Project Deployment framework. The deployment process itself completes successfully, and the generated library compiles and runs correctly on my ESP32. However, when executing inference, the serial console reports:

run_classifier error -6

The issue only occurs when combining projects 1032227 and 995604 in a multi-project deployment.

Project ID:

  • 1032227
  • 995604

Context/Use case:

I am deploying multiple Edge Impulse models on a single ESP32 using the Multi-Project Deployment framework. The goal is to run inference on both models from the same firmware image.

I have previously performed a successful multi-project deployment using projects 995604 and 1014976, which suggests that the deployment workflow and integration code are correct. The problem appears to be related specifically to project 1032227.

Steps Taken:

  1. Exported the Edge Impulse libraries for projects 1032227 and 995604.
  2. Created a Multi-Project Deployment following the Edge Impulse documentation.
  3. Successfully compiled and flashed the firmware to an ESP32.
  4. Verified that the application starts correctly.
  5. Executed inference using run_classifier().
  6. Observed that the classifier returns run_classifier error -6.

Additional tests:

  • Deploying project 995604 alone works correctly.
  • Deploying project 1032227 alone works correctly.
  • A multi-project deployment using projects 995604 and 1014976 works correctly.
  • The issue only appears when combining projects 1032227 and 995604.

Expected Outcome:

Both models should initialize and run inference successfully within the multi-project deployment environment.

Actual Outcome:

Inference fails with:

run_classifier error -6

when using projects 1032227 and 995604 together.

Reproducibility:

  • [x] Always
  • [ ] Sometimes
  • [ ] Rarely

Environment:

  • Platform: ESP32
  • Build Environment Details: Arduino IDE
  • OS Version: Windows
  • Edge Impulse Version (Library Deployment): [Please let me know if a specific version number is required and where I should verify it.]
  • Edge Impulse CLI Version: N/A
  • Project Version: Latest versions of the projects
  • Custom Blocks / Impulse Configuration: Standard Edge Impulse deployment, no custom DSP or custom learning blocks.

Logs/Attachments:

Serial output:

run_classifier error -6

I can provide the full serial log, impulse configurations, and deployment libraries if needed.

Additional Information:

Since:

  • Project 995604 works individually.
  • Project 1032227 works individually.
  • Multi-project deployment works with projects 995604 and 1014976.

I suspect there may be a compatibility issue, memory conflict, generated symbol conflict, or model-specific configuration in project 1032227 that causes run_classifier() to fail when used in a multi-project deployment.

Has anyone encountered a similar issue, or can someone explain what error code -6 specifically indicates in the context of Multi-Project Deployments?

Hello @gomezan,

Here are the errors that can be returned by the C++ SDK:

The EI_IMPULSE_TFLITE_ARENA_ALLOC_FAILED (or -6) is a failure to allocate memory in TensorFlow Lite arena, often caused by a lack of available heap memory.
In short, it is a memory issue.

Also, if you have a look in the model_metadata.h, there is an option to increase the EI_CLASSIFIER_TFLITE_LARGEST_ARENA_SIZE

Also what is your Arduino IDE version and ESP Core version?
And which ESP32 board are you using? If it has PSRAM, is it enabled?

enable psram

Let us know, I can also check with our embedded team if there is a way to clear the memory in between the 2 inferences.
Would it be possible for you to share your code by any chance, or are you just using the static buffer example?

Best,

Louis

Hi Louis,

Thank you very much for your response and for looking into this.

I have already enabled PSRAM in the Arduino IDE, and I am also using the Maximum 7.9 MB APP (No OTA / No FS) partition scheme. Additionally, I have gradually increased EI_CLASSIFIER_TFLITE_LARGEST_ARENA_SIZE from its default value all the way up to 559872 bytes, but unfortunately the behavior remains the same.

The example I’m using is almost identical to the default static buffer example generated by Edge Impulse for the multi-project deployment.

The structure is essentially:

/* Edge Impulse ingestion SDK
 * Copyright (c) 2022 EdgeImpulse Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */

/* Includes ---------------------------------------------------------------- */
#include <stdio.h>
#include "src/edge-impulse-sdk/classifier/ei_run_classifier.h"



// Raw features copied from test sample
static const float features_impulse_1032227_2[100] = {0};

static const float features_impulse_995604_1[100] = {0};


/**
 * @brief      Arduino setup function
 */
void setup()
{
    // put your setup code here, to run once:
    Serial.begin(115200);
    // comment out the below line to cancel the wait for USB connection (needed for native USB)
    while (!Serial);
    Serial.println("Edge Impulse Inferencing Demo");
}

/**
 * @brief      Arduino main function
 */
void loop()
{
    // project 1032227, impulse 2
    {
        ei_printf("Impulse #1 (project 1032227, impulse 2):\n");

        signal_t signal;            // Wrapper for raw input buffer
        ei_impulse_result_t result; // Used to store inference output
        EI_IMPULSE_ERROR res;       // Return code from inference

        const ei_impulse_t& impulse = impulse_1032227_2;
        ei_impulse_handle_t& impulse_handle = impulse_handle_1032227_2;

        run_classifier_init(&impulse_handle);

        // Calculate the length of the buffer
        size_t buf_len = sizeof(features_impulse_1032227_2) / sizeof(features_impulse_1032227_2[0]);

        // Make sure that the length of the buffer matches expected input length
        if (buf_len != impulse.dsp_input_frame_size) {

            while(1){
                ei_printf("ERROR: The size of the input buffer is not correct.\n");
                ei_printf("Expected %d items, but got %d\n",
                    impulse.dsp_input_frame_size,
                    (int)buf_len);
            }
            
    
        }

        int err = numpy::signal_from_buffer(features_impulse_1032227_2, impulse.dsp_input_frame_size, &signal);
        if (err != 0) {

            while(1){
                ei_printf("signal_from_buffer failed (%d)\n", err);
            }
           
        }

        // Perform DSP pre-processing and inference
        res = run_classifier(&impulse_handle, &signal, &result, false);
        if (res != EI_IMPULSE_OK) {

            while(1){
                ei_printf("run_classifier returned: %d\n", res);
            }
            
        }

        // See how to modify this in src/edge-impulse-sdk/classifier/ei_print_results.h
        ei_print_results(&impulse_handle, &result);
        ei_printf("\n");

        run_classifier_deinit(&impulse_handle);
    }

     // project 995604, impulse 1
    {
        ei_printf("Impulse #2 (project 995604, impulse 1):\n");

        signal_t signal;            // Wrapper for raw input buffer
        ei_impulse_result_t result; // Used to store inference output
        EI_IMPULSE_ERROR res;       // Return code from inference

        const ei_impulse_t& impulse = impulse_995604_1;
        ei_impulse_handle_t& impulse_handle = impulse_handle_995604_1;

        run_classifier_init(&impulse_handle);

        // Calculate the length of the buffer
        size_t buf_len = sizeof(features_impulse_995604_1) / sizeof(features_impulse_995604_1[0]);

        // Make sure that the length of the buffer matches expected input length
        if (buf_len != impulse.dsp_input_frame_size) {

            while(1){
                
                ei_printf("ERROR: The size of the input buffer is not correct.\n");
                ei_printf("Expected %d items, but got %d\n",
                    impulse.dsp_input_frame_size,
                    (int)buf_len);
            }
            
        }

        int err = numpy::signal_from_buffer(features_impulse_995604_1, impulse.dsp_input_frame_size, &signal);
        if (err != 0) {
            
            while(1){
                ei_printf("signal_from_buffer failed (%d)\n", err);
            }
            
        }

        // Perform DSP pre-processing and inference
        res = run_classifier(&impulse_handle, &signal, &result, false);
        if (res != EI_IMPULSE_OK) {

            while(1){
                ei_printf("run_classifier returned: %d\n", res);
            }
            
        }

        // See how to modify this in edge-impulse-sdk/classifier/ei_print_results.h
        ei_print_results(&impulse_handle, &result);
        ei_printf("\n");

        run_classifier_deinit(&impulse_handle);
    }

    delay(1000);
}


Regarding my setup:

  • Board: ESP32-S3
  • PSRAM: Enabled (OPI PSRAM)
  • Partition scheme: Maximum 7.9 MB APP (No OTA / No FS)
  • Arena size: Increased up to 559872 bytes

If your embedded team has any suggestions on how to completely release the TensorFlow Lite arena (or any other memory allocated by run_classifier_init()) between inferences, I’d be very interested to try them.

Thank you again for your help!

Best regards,
Andrés