Question/Issue:
I am trying to run an Edge Impulse image classification model (cat vs. dog) on an ESP32-S3 board using an RGB image stored in a .h
file (not using the camera input). The image is manually resized and passed as RGB888 values to the resized_matrix->item
, then classified using run_classifier()
.
However, during inference, I encounter the following error:
“Failed to allocate persistent buffer of size 512, does not fit in tensor arena and reached EI_MAX_OVERFLOW_BUFFER_COUNT”
To address this, I have:
- Enabled OPI PSRAM in the board settings.
- Selected the “Huge APP (3MB No OTA/1MB SPIFFS)” partition scheme.
- Added
#define EI_TENSOR_ARENA_LOCATION ".psram"
in my sketch. - Tried manually increasing the tensor arena size by editing the following files:
- In
model_variables.h
:#define EI_CLASSIFIER_TFLITE_ARENA_SIZE (512 * 1024)
- In
model_metadata.h
:#define EI_CLASSIFIER_TFLITE_LARGEST_ARENA_SIZE (1024 * 1024)
- In
Despite these adjustments, the error still persists. Is there any additional configuration needed to fully allocate the tensor arena in PSRAM or allow persistent buffer allocation to succeed?
Project ID:
743568
Context/Use case:
I am deploying an image classification model (cat vs. dog) trained on Edge Impulse and exported as an Arduino library. I use an ESP32-S3-N16R8 development board with Arduino IDE.
Instead of capturing live images from the ESP32-CAM, I import a test image stored as a .h
file (converted from JPEG to RGB format) and assign its pixel data to resized_matrix
.
Then, I run inference using run_classifier()
, but I encountered a memory allocation error like:
Failed to allocate persistent buffer of size 1024, does not fit in tensor arena and reached EI_MAX_OVERFLOW_BUFFER_COUNT
I’ve enabled PSRAM and selected a large partition scheme (Huge APP 3MB), but the issue persists. This prevents me from running any inference.
Steps Taken:
- Trained a cat vs. dog image classification model on Edge Impulse Studio (web version).
- Exported the model as an Arduino library (
.zip
) and imported it into Arduino IDE 2.3.6. - Converted a test JPEG image to
.h
format with RGB888 array using Python, and embedded it into the sketch. - Used
resized_matrix->item
to store the pixel array and passed it torun_classifier()
. - Enabled PSRAM (
OPI PSRAM
) and selected partition scheme:Huge APP (3MB No OTA/1MB SPIFFS)
. - Encountered runtime error:
Failed to allocate persistent buffer of size 1024, does not fit in tensor arena and reached EI_MAX_OVERFLOW_BUFFER_COUNT
.
Expected Outcome:
[Describe what you expected to happen]
Actual Outcome:
[Describe what actually happened]
Reproducibility:
- [╳ ] Always
- [ ] Sometimes
- [ ] Rarely
Environment:
- Platform: [ESP32-S3-N16R8]
- Build Environment Details: [ Arduino IDE 2.3.6]
- OS Version: [Windows 10]
- Edge Impulse Version (Firmware): [1.73.4]
- To find out Edge Impulse Version:
- if you have pre-compiled firmware: run edge-impulse-run-impulse --raw and type AT+INFO. Look for Edge Impulse version in the output.
- if you have a library deployment: inside the unarchived deployment, open model-parameters/model_metadata.h and look for EI_STUDIO_VERSION_MAJOR, EI_STUDIO_VERSION_MINOR, EI_STUDIO_VERSION_PATCH
- Edge Impulse CLI Version: Using Edge Impulse Studio Web
- Project Version: Latest, exported as Arduino Library on July 2025
-
Custom Blocks / Impulse Configuration:
- Image classification model
- Input shape: 96x96x3 RGB
- Uses image data from manually resized and embedded
.h
file - DSP: “Resize and Scale”
- No anomaly detection
Logs/Attachments:
Additional Information:
This is the main code of Arduino IDE, kindly check.
#define EI_CLASSIFIER_ALLOCATION_STATIC 1
#define EI_TENSOR_ARENA_LOCATION ".psram"
#include <esp32-cam-cat-dog_inferencing.h>
#include "cutecat.h" // Your JPEG image file .h
#include "esp_heap_caps.h"
#include "img_converters.h" // ESP32 Camera Library
#include "image_util.h" // ESP32 Camera Library
dl_matrix3du_t *resized_matrix = NULL;
// Decode the JPEG array and resize it
bool jpeg_decode_and_resize() {
Serial.println("Decoding JPEG...");
dl_matrix3du_t *rgb888_matrix = dl_matrix3du_alloc(1, cutecat_width, cutecat_height, 3);
if (!rgb888_matrix) {
Serial.println("Allocate rgb888_matrix failed!");
return false;
}
if (!fmt2rgb888((uint8_t*)cutecat, cutecat_len, PIXFORMAT_JPEG, rgb888_matrix->item)) {
Serial.println("JPEG decode failed!");
dl_matrix3du_free(rgb888_matrix);
return false;
}
Serial.println("Resizing image...");
resized_matrix = dl_matrix3du_alloc(1, EI_CLASSIFIER_INPUT_WIDTH, EI_CLASSIFIER_INPUT_HEIGHT, 3);
if (!resized_matrix) {
Serial.println("Allocate resized_matrix failed!");
dl_matrix3du_free(rgb888_matrix);
return false;
}
image_resize_linear(resized_matrix->item, rgb888_matrix->item,
EI_CLASSIFIER_INPUT_WIDTH, EI_CLASSIFIER_INPUT_HEIGHT, 3,
cutecat_width, cutecat_height);
dl_matrix3du_free(rgb888_matrix);
Serial.println("Image ready for inference!");
return true;
}
// Convert to the input format required by the EI model
int raw_feature_get_data(size_t offset, size_t out_len, float *signal_ptr) {
size_t pixel_ix = offset * 3;
size_t bytes_left = out_len;
size_t out_ptr_ix = 0;
while (bytes_left != 0) {
uint8_t r = resized_matrix->item[pixel_ix];
uint8_t g = resized_matrix->item[pixel_ix + 1];
uint8_t b = resized_matrix->item[pixel_ix + 2];
float pixel_f = (r << 16) + (g << 8) + b;
signal_ptr[out_ptr_ix] = pixel_f;
out_ptr_ix++;
pixel_ix += 3;
bytes_left--;
}
return 0;
}
void setup() {
Serial.begin(115200);
Serial.println("=== Serial Begin ===");
Serial.println("=== Edge Impulse JPEG image inference test ===");
if (!psramFound()) {
Serial.println("❌ PSRAM not detected. Please make sure it is enabled!");
while (1);
}
if (!jpeg_decode_and_resize()) {
Serial.println("Image prepare failed!");
while (1);
}
//
Serial.printf("Free internal heap (DRAM): %d bytes\n", heap_caps_get_free_size(MALLOC_CAP_INTERNAL));
Serial.printf("Free PSRAM: %d bytes\n", heap_caps_get_free_size(MALLOC_CAP_SPIRAM));
signal_t signal;
signal.total_length = EI_CLASSIFIER_INPUT_WIDTH *
EI_CLASSIFIER_INPUT_HEIGHT *
EI_CLASSIFIER_INPUT_FRAMES;
signal.get_data = &raw_feature_get_data;
ei_impulse_result_t result = {};
EI_IMPULSE_ERROR res = run_classifier(&signal, &result, false);
if (res != EI_IMPULSE_OK) {
Serial.print("❌ Inference failed!Error code: ");
Serial.println(res);
return;
}
float max_score = 0.0f;
const char* predicted = "";
for (size_t ix = 0; ix < EI_CLASSIFIER_LABEL_COUNT; ix++) {
float score = result.classification[ix].value;
const char* label = result.classification[ix].label;
Serial.printf(" %s: %.3f\n", label, score);
if (score > max_score) {
max_score = score;
predicted = label;
}
}
Serial.printf("➡️ Prediction result: %s (%.2f%%)\n", predicted, max_score * 100);
#if EI_CLASSIFIER_HAS_ANOMALY == 1
Serial.printf("Anomaly score: %.3f\n", result.anomaly);
#endif
dl_matrix3du_free(resized_matrix);
Serial.println("=== Inference completed ===");
}
void loop() {
}