Issues running image model (C SDK)

Project ID: Dog Doorbell - Dashboard - Edge Impulse

I am attempting to compile this project using your provided C SDK. It gets compiled to WASM (using an in-house toolchain — I cannot use the WASM deployments you provide) successfully using the CMake file below. I have successfully used the same CMake file to compile and run the Motion Recognition example you provide (Motion recognition with anomaly detection - Edge Impulse Documentation).

I am now attempting to do the same with the vision model I created. To simplify things, I am providing an all black frame just to see if I can get inference running (baby steps!), but when I run inference I get this error:

    Running impulse...
    ERR: input tensor has size 4 bytes, but input matrix has has size 307200 bytes
    run_classifier returned: -24
    Begin output
    [0.00000]
    End output

I am preparing my input sample using the following methods:

static float features[EI_CLASSIFIER_DSP_INPUT_FRAME_SIZE];
static size_t feature_ix = 0;

// helper to pack RGB888 into a float’s mantissa (0xRRGGBB)
static inline float pack_rgb888_u32_to_f32(uint8_t r, uint8_t g, uint8_t b) {
    uint32_t u = ((uint32_t)r << 16) | ((uint32_t)g << 8) | (uint32_t)b;
    float f;
    memcpy(&f, &u, sizeof(f));
    return f;
}

int get_feature_data(size_t offset, size_t length, float *out_ptr) {
    printf("get_feature_data: offset=%lu, length=%lu\n", offset, length);
    memcpy(out_ptr, features + offset, length * sizeof(float));
    return 0;
}

and

for (int i = 0; i < EI_CLASSIFIER_INPUT_WIDTH * EI_CLASSIFIER_INPUT_HEIGHT; i++) {
        features[feature_ix++] = pack_rgb888_u32_to_f32(0, 0, 0);
    }

    signal_t signal;
    signal.total_length = EI_CLASSIFIER_RAW_SAMPLE_COUNT; // 102400
    signal.get_data = &get_feature_data;

    ei_impulse_result_t result;

    EI_IMPULSE_ERROR res = run_classifier(&signal, &result, true);
    printf("run_classifier returned: %d\n", res);

    printf("Begin output\n");

Here’s the CMake file I am using:

cmake_minimum_required(VERSION 3.20.0)

# Set the WASI SDK toolchain file
set(CMAKE_TOOLCHAIN_FILE /opt/wasi-sdk/share/cmake/wasi-sdk-p1.cmake)

# Set build type to Release
set(CMAKE_BUILD_TYPE Release)

# Project name
set(APPNAME edge-impulse-standalone)
project(${APPNAME})

# Set compilation flags
add_compile_options(
    # --target=wasm32-wasi
    -Os
    -DNDEBUG
    -Wall
    -DEI_PORTING_POSIX=1              # Force POSIX port for WASM
    -DUSE_CMSIS_NN=OFF                # Compiling for OSX
    -DEI_LOG_LEVEL=4                  # Debug logging
    -DTF_LITE_DISABLE_X86_NEON=1
    -DEIDSP_SIGNAL_C_FN_POINTER=1
    -DEI_C_LINKAGE=1
    -fno-exceptions                   # Turn off exceptions for WASM
    -Wno-strict-aliasing
    -Wno-unknown-attributes
    -I${CMAKE_SOURCE_DIR}
)

# Set C++ standard for C++ files
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

# Set linker flags
add_link_options(
    -Wl,--strip-all
    -lm
)

# Define source files (mirroring Makefile)
set(CSOURCES
    ${CMAKE_SOURCE_DIR}/edge-impulse-sdk/tensorflow/lite/c/common.c
    ${CMAKE_SOURCE_DIR}/edge-impulse-sdk/CMSIS/DSP/Source/BasicMathFunctions/*.c
    ${CMAKE_SOURCE_DIR}/edge-impulse-sdk/CMSIS/DSP/Source/FastMathFunctions/*.c
    ${CMAKE_SOURCE_DIR}/edge-impulse-sdk/CMSIS/DSP/Source/StatisticsFunctions/*.c
    ${CMAKE_SOURCE_DIR}/edge-impulse-sdk/CMSIS/DSP/Source/TransformFunctions/*fft*.c
    ${CMAKE_SOURCE_DIR}/edge-impulse-sdk/CMSIS/DSP/Source/CommonTables/*.c
    ${CMAKE_SOURCE_DIR}/edge-impulse-sdk/CMSIS/DSP/Source/TransformFunctions/*bit*.c
)

set(CXXSOURCES
    ${CMAKE_SOURCE_DIR}/tflite-model/*.cpp
    ${CMAKE_SOURCE_DIR}/edge-impulse-sdk/dsp/kissfft/*.cpp
    ${CMAKE_SOURCE_DIR}/edge-impulse-sdk/dsp/dct/*.cpp
    ${CMAKE_SOURCE_DIR}/edge-impulse-sdk/dsp/memory.cpp
    ${CMAKE_SOURCE_DIR}/edge-impulse-sdk/classifier/*.cpp
    ${CMAKE_SOURCE_DIR}/edge-impulse-sdk/porting/posix/*.c*
    ${CMAKE_SOURCE_DIR}/edge-impulse-sdk/porting/mingw32/*.c*
    ${CMAKE_SOURCE_DIR}/edge-impulse-sdk/tensorflow/lite/kernels/*.cc
    ${CMAKE_SOURCE_DIR}/edge-impulse-sdk/tensorflow/lite/kernels/internal/*.cc
    ${CMAKE_SOURCE_DIR}/edge-impulse-sdk/tensorflow/lite/micro/kernels/*.cc
    ${CMAKE_SOURCE_DIR}/edge-impulse-sdk/tensorflow/lite/micro/*.cc
    ${CMAKE_SOURCE_DIR}/edge-impulse-sdk/tensorflow/lite/micro/memory_planner/*.cc
    ${CMAKE_SOURCE_DIR}/edge-impulse-sdk/tensorflow/lite/core/api/*.cc
)

set(APP_CSOURCES
    ${CMAKE_SOURCE_DIR}/source/main.c
)

# Optional CMSIS-NN sources
# option(USE_CMSIS_NN "Enable CMSIS-NN optimizations" OFF)
# if(USE_CMSIS_NN)
#     add_compile_options(
#         -DEI_CLASSIFIER_TFLITE_ENABLE_CMSIS_NN=1
#         -D__ARM_FEATURE_DSP=1
#         -D__GNUC_PYTHON__=1
#         -I${CMAKE_SOURCE_DIR}/edge-impulse-sdk/CMSIS/NN/Include/
#         -I${CMAKE_SOURCE_DIR}/edge-impulse-sdk/CMSIS/DSP/PrivateInclude/
#     )
#     list(APPEND CSOURCES
#         ${CMAKE_SOURCE_DIR}/edge-impulse-sdk/CMSIS/NN/Source/ActivationFunctions/*.c
#         ${CMAKE_SOURCE_DIR}/edge-impulse-sdk/CMSIS/NN/Source/BasicMathFunctions/*.c
#         ${CMAKE_SOURCE_DIR}/edge-impulse-sdk/CMSIS/NN/Source/ConcatenationFunctions/*.c
#         ${CMAKE_SOURCE_DIR}/edge-impulse-sdk/CMSIS/NN/Source/ConvolutionFunctions/*.c
#         ${CMAKE_SOURCE_DIR}/edge-impulse-sdk/CMSIS/NN/Source/FullyConnectedFunctions/*.c
#         ${CMAKE_SOURCE_DIR}/edge-impulse-sdk/CMSIS/NN/Source/NNSupportFunctions/*.c
#         ${CMAKE_SOURCE_DIR}/edge-impulse-sdk/CMSIS/NN/Source/PoolingFunctions/*.c
#         ${CMAKE_SOURCE_DIR}/edge-impulse-sdk/CMSIS/NN/Source/ReshapeFunctions/*.c
#         ${CMAKE_SOURCE_DIR}/edge-impulse-sdk/CMSIS/NN/Source/SoftmaxFunctions/*.c
#     )
# endif()

# Glob source files
file(GLOB CSOURCE_FILES ${CSOURCES})
file(GLOB CXXSOURCE_FILES ${CXXSOURCES})
file(GLOB APP_CSOURCE_FILES ${APP_CSOURCES})

# Create executable
add_executable(${APPNAME}.wasm ${CSOURCE_FILES} ${CXXSOURCE_FILES} ${APP_CSOURCE_FILES})

# Link libraries (math library included via add_link_options)
target_link_libraries(${APPNAME}.wasm PRIVATE m)

Lastly, I had to make one change to the POSIX porting file to make this compatible with my WASM toolchain:

// #if EI_CLASSIFIER_USE_GPU_DELEGATES==1
    clockid_t clock_id = CLOCK_MONOTONIC;
// #else
//    clockid_t clock_id = CLOCK_PROCESS_CPUTIME_ID;
// #endif

Our toolchain only supports CLOCK_MONOTONIC.

Environment:

  • Platform: aarch64 Docker container, but targeting Raspi 5
  • OS Version: Ubuntu 22.04 / Raspbian Bookworm
  • Edge Impulse Version (Firmware): 1.74.30

How can I go about debugging this? My other model worked just fine and I’m confused as to why I am having issues with this specific one.

Hi @DanKoubaAtym,

The error indicates there’s a mismatch with your input matrix and the model’s input. Can you confirm that you have exported a vision model? Can you also confirm the input dimensions of the TFLite model in a program like Netron? You can obtained the TFLite file from the project’s dashboard.
Furthermore can you also confirm that when you exported the vision model that you updated the model-parameters/, tflite-model and the edge-impulse-sdk/ directories?

// Raul

Hey Raul! I went into my project, downloaded the TFLite (float32) model from the Dashboard, and put it into Netron — the dimensions look correct to me:

I tried rebuilding everything and using the existing makefile in the C standalone inference repository to reduce variables (along with my modifications to main.c that create an empty vector to run inference on). When I do so, I get a segmentation fault after inference starts and the data is loaded in. I verified the latter with logging. The snippet is below:

get_feature_data: offset=98304, length=1024
get_feature_data: offset=99328, length=1024
get_feature_data: offset=100352, length=1024
get_feature_data: offset=101376, length=1024
[1]    35763 segmentation fault  ./build/edge-impulse-standalone

If I rebuild using my CMake workflow that targets WASM, and I get the same size mismatch as before:

get_feature_data: offset=98304, length=1024
get_feature_data: offset=99328, length=1024
get_feature_data: offset=100352, length=1024
get_feature_data: offset=101376, length=1024
ERR: input tensor has size 4 bytes, but input matrix has has size 307200 bytes
run_classifier returned: -24
Begin output
[0.00000]
End output

My project is public — could you try this yourself? My entire main.c file is below for you to try:

#include <stdlib.h>
#include <stdint.h>
#include <stdio.h>
#include "edge-impulse-sdk/dsp/numpy_types.h"
#include "edge-impulse-sdk/porting/ei_classifier_porting.h"
#include "edge-impulse-sdk/classifier/ei_classifier_types.h"

static float features[EI_CLASSIFIER_DSP_INPUT_FRAME_SIZE];
static size_t feature_ix = 0;

// helper to pack RGB888 into a float’s mantissa (0xRRGGBB)
static inline float pack_rgb888_u32_to_f32(uint8_t r, uint8_t g, uint8_t b) {
    uint32_t u = ((uint32_t)r << 16) | ((uint32_t)g << 8) | (uint32_t)b;
    float f;
    memcpy(&f, &u, sizeof(f));
    return f;
}

int get_feature_data(size_t offset, size_t length, float *out_ptr) {
    printf("get_feature_data: offset=%lu, length=%lu\n", offset, length);
    memcpy(out_ptr, features + offset, length * sizeof(float));
    return 0;
}

EI_IMPULSE_ERROR run_classifier(signal_t *, ei_impulse_result_t *, bool);

int main(int argc, char **argv) {

    printf("EI Hello World!\n");

    for (int i = 0; i < EI_CLASSIFIER_INPUT_WIDTH * EI_CLASSIFIER_INPUT_HEIGHT; i++) {
        features[feature_ix++] = pack_rgb888_u32_to_f32(0, 0, 0);
    }

    signal_t signal;
    signal.total_length = EI_CLASSIFIER_RAW_SAMPLE_COUNT; // 102400
    signal.get_data = &get_feature_data;

    ei_impulse_result_t result;

    EI_IMPULSE_ERROR res = run_classifier(&signal, &result, false);
    printf("run_classifier returned: %d\n", res);

    printf("Begin output\n");

    // print the predictions
    printf("[");
    for (size_t ix = 0; ix < EI_CLASSIFIER_LABEL_COUNT; ix++) {
        printf("%.5f", result.classification[ix].value);
#if EI_CLASSIFIER_HAS_ANOMALY == 1
        printf(", ");
#else
        if (ix != EI_CLASSIFIER_LABEL_COUNT - 1) {
            printf(", ");
        }
#endif
    }
#if EI_CLASSIFIER_HAS_ANOMALY == 1
    printf("%.3f", result.anomaly);
#endif
    printf("]\n");

    printf("End output\n");
}

Quick update: I was able to take my raw model and run it with the expected input size using TFLite. So the difference here lies with the Edge Impulse SDKs, as far as I can tell.

Hi @DanKoubaAtym,

I tried your model with the example standalone repo together with a Raw feature sample from your project and it worked well. There must be something wrong in your application. Take a look at source/main.cpp in said repo.

I also noticed that you’re pack_rgb888_u32_to_f32 give incorrect results. We don’t want a memcpy here. Test your function with values other than 0 and you’ll see.

Can you change it to:

static inline float pack_rgb888_u32_to_f32(uint8_t r, uint8_t g, uint8_t b) {
    return (float)((uint32_t)r << 16) + ((uint32_t)g << 8) + (uint32_t)b;
}

Also feature_ixx being global looks suspicious. I don’t know if it’s necesarry to be global and you don’t reference anywhere else but 1 place. Can you replace it with i in the for-loop and see if that helps.

// Raul