Skip to content

Commit 4310dd6

Browse files
Added MobileNet V2 examples
- Added two examples showcasing how to use mobilenet v2 using `esp-tflite-micro` - `examples/mobilenet` shows how to use int8 quantized mobilenet v2 model with alpha = 0.35 - `examples/mobilenet` shows how to use a model with a custom classifier head using mobilenetv2 as its base model
1 parent 78e5532 commit 4310dd6

30 files changed

+251166
-0
lines changed

examples/mobilenet/CMakeLists.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
cmake_minimum_required(VERSION 3.5)
2+
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
3+
project(mobilenet)

examples/mobilenet/README.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
2+
This example shows how to run a MobileNet V2 model using `esp-tflite-micro`.
3+
The model is int8 quantised with `alpha=0.35`.
4+
5+
**Note:-** MobileNet V2's classifier head can be easily modified to detect a custom number of labels after some re-training and fine-tuning. We have created another example to show how to do this along with a jupyter notebook to generate your own custom models. Check it out in the `mobilenet_custom` example.
6+
7+
## How to test with your own images?
8+
This example uses raw image data stored in `image.cc` file. You can easily run it with your own images by doing the following:-
9+
10+
1. Convert image to raw format
11+
```bash
12+
python img_convert.py <img_path>
13+
```
14+
15+
2. Convert raw file to .cc file
16+
```bash
17+
xxd -i <raw_img_path> >> main/image.cc
18+
```
19+
20+
3. Rename variables and add `image.h` header include in `image.cc`

examples/mobilenet/img_convert.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
2+
import sys
3+
import numpy as np
4+
from tensorflow.keras.utils import load_img, img_to_array
5+
from array import array
6+
7+
def convert_and_save(path):
8+
img = img_to_array(load_img(path, target_size=(224, 224)))
9+
img = array('B', img.flatten().astype(np.uint8))
10+
with open("img.raw", "wb") as f:
11+
f.write(img)
12+
13+
if __name__ == "__main__":
14+
if len(sys.argv) < 2:
15+
print("Usage: python image_convert.py img_path")
16+
exit(0)
17+
18+
img_path = sys.argv[1]
19+
convert_and_save(img_path)
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
idf_component_register(
2+
SRCS "main.cc" "model.cc" "image.cc"
3+
PRIV_REQUIRES
4+
INCLUDE_DIRS "")
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
dependencies:
2+
espressif/esp-tflite-micro:
3+
version: "*"
4+
override_path: "../../../"

examples/mobilenet/main/image.cc

Lines changed: 12549 additions & 0 deletions
Large diffs are not rendered by default.

examples/mobilenet/main/image.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
2+
#pragma once
3+
4+
extern const unsigned char image_raw[];
5+
extern const unsigned int image_raw_len;

examples/mobilenet/main/main.cc

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
2+
#include <freertos/FreeRTOS.h>
3+
#include <esp_log.h>
4+
#include <esp_timer.h>
5+
6+
#include <tensorflow/lite/micro/micro_interpreter.h>
7+
#include <tensorflow/lite/micro/micro_log.h>
8+
#include <tensorflow/lite/micro/micro_profiler.h>
9+
#include <tensorflow/lite/micro/micro_mutable_op_resolver.h>
10+
#include <tensorflow/lite/schema/schema_generated.h>
11+
12+
#include "model.h"
13+
#include "image.h"
14+
15+
static const char* TAG = "mobilenet";
16+
17+
namespace {
18+
const tflite::Model* model = nullptr;
19+
tflite::MicroInterpreter* interpreter = nullptr;
20+
21+
constexpr int kTensorArenaSize = 1.5 * 1024 * 1024;
22+
static uint8_t* tensor_arena;
23+
24+
TfLiteTensor* input;
25+
TfLiteTensor* output;
26+
}
27+
28+
int8_t quantize(float val) {
29+
auto zero_point = input->params.zero_point;
30+
auto scale = input->params.scale;
31+
return (val / scale) + zero_point;
32+
}
33+
34+
float dequantize(int8_t val) {
35+
auto zero_point = output->params.zero_point;
36+
auto scale = output->params.scale;
37+
return (val - zero_point) * scale;
38+
}
39+
40+
extern "C" void app_main(void)
41+
{
42+
model = tflite::GetModel(esp_mobile_net_model);
43+
if (model->version() != TFLITE_SCHEMA_VERSION) {
44+
MicroPrintf("Model provided is schema version %d not equal to supported version %d.", model->version(), TFLITE_SCHEMA_VERSION);
45+
}
46+
47+
if (tensor_arena == NULL) {
48+
tensor_arena = (uint8_t*)heap_caps_malloc(kTensorArenaSize, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT);
49+
}
50+
51+
if (tensor_arena == NULL) {
52+
printf("Couldn't allocate memory of %d bytes\n", kTensorArenaSize);
53+
return;
54+
}
55+
56+
ESP_LOGI(TAG, "Allocated memory for Tensor Arena");
57+
58+
static tflite::MicroMutableOpResolver<7> micro_op_resolver;
59+
micro_op_resolver.AddRelu6();
60+
micro_op_resolver.AddConv2D();
61+
micro_op_resolver.AddDepthwiseConv2D();
62+
micro_op_resolver.AddAdd();
63+
micro_op_resolver.AddMean();
64+
micro_op_resolver.AddFullyConnected();
65+
micro_op_resolver.AddSoftmax();
66+
67+
static tflite::MicroInterpreter static_interpreter(
68+
model, micro_op_resolver, tensor_arena, kTensorArenaSize
69+
);
70+
interpreter = &static_interpreter;
71+
72+
if (interpreter->AllocateTensors() != kTfLiteOk) {
73+
MicroPrintf("AllocateTensors() failed");
74+
return;
75+
}
76+
77+
ESP_LOGI(TAG, "Allocated Tensors");
78+
79+
input = interpreter->input(0);
80+
output = interpreter->output(0);
81+
82+
for (int i = 0; i < image_raw_len; i++) {
83+
input->data.int8[i] = quantize(((uint8_t)image_raw[i] / 127.5) - 1);
84+
}
85+
86+
long long start_time = esp_timer_get_time();
87+
88+
if (interpreter->Invoke() != kTfLiteOk) {
89+
MicroPrintf("Invoke() failed");
90+
}
91+
92+
long long total_time = esp_timer_get_time() - start_time;
93+
ESP_LOGI(TAG, "Invoke was successful");
94+
printf("Invoke: Total time = %lld\n", total_time / 1000);
95+
96+
int maxLabel = 0;
97+
float maxConf = 0.0;
98+
99+
for (int i = 0; i < 1000; i++) {
100+
float conf = dequantize(output->data.int8[i]);
101+
if (conf > maxConf) {
102+
maxLabel = i;
103+
maxConf = conf;
104+
}
105+
}
106+
107+
printf("\nLabel: %d, Confidence: %f\n", maxLabel, maxConf);
108+
}

0 commit comments

Comments
 (0)