feat: Add unity test for wakenet and multinet API

This commit is contained in:
sxy 2023-03-20 16:38:28 +08:00
parent 4ef08bb606
commit 0cf2db1540
10 changed files with 16821 additions and 21 deletions

View File

@ -1,6 +1,6 @@
if(IDF_TARGET STREQUAL "esp32")
set(COMPONENT_ADD_INCLUDEDIRS
src/include
src/include
esp-tts/esp_tts_chinese/include
include/esp32
)

View File

@ -2,6 +2,7 @@ import io
import os
import argparse
import shutil
import math
from pack_model import pack_models
def calculate_total_size(folder_path):
@ -64,23 +65,25 @@ def copy_multinet_from_sdkconfig(model_path, sdkconfig_path, target_path):
models_string += label
models = []
if "CONFIG_SR_MN_CN_MULTINET3_SINGLE_RECOGNITION" in models_string and len(models) < 2:
if "CONFIG_SR_MN_CN_MULTINET3_SINGLE_RECOGNITION" in models_string:
models.append('mn3_cn')
elif "CONFIG_SR_MN_CN_MULTINET4_5_SINGLE_RECOGNITION_QUANT8" in models_string:
models.append('mn4q8_cn')
elif "CONFIG_SR_MN_CN_MULTINET4_5_SINGLE_RECOGNITION" in models_string and len(models) < 2:
elif "CONFIG_SR_MN_CN_MULTINET4_5_SINGLE_RECOGNITION" in models_string:
models.append('mn4_cn')
elif "CONFIG_SR_MN_CN_MULTINET5_RECOGNITION_QUANT8" in models_string and len(models) < 2:
elif "CONFIG_SR_MN_CN_MULTINET5_RECOGNITION_QUANT8" in models_string:
models.append('mn5q8_cn')
elif "CONFIG_SR_MN_EN_MULTINET5_SINGLE_RECOGNITION_QUANT8" in models_string and len(models) < 2:
models.append('mn5q8_en')
elif "CONFIG_SR_MN_EN_MULTINET5_SINGLE_RECOGNITION" in models_string and len(models) < 2:
models.append('mn5_en')
elif "CONFIG_SR_MN_EN_MULTINET6_QUANT" in models_string and len(models) < 2:
models.append('mn6_en')
elif "CONFIG_SR_MN_CN_MULTINET6_QUANT" in models_string and len(models) < 2:
elif "CONFIG_SR_MN_CN_MULTINET6_QUANT" in models_string:
models.append('mn6_cn')
if "CONFIG_SR_MN_EN_MULTINET5_SINGLE_RECOGNITION_QUANT8" in models_string:
models.append('mn5q8_en')
elif "CONFIG_SR_MN_EN_MULTINET5_SINGLE_RECOGNITION" in models_string:
models.append('mn5_en')
elif "CONFIG_SR_MN_EN_MULTINET6_QUANT" in models_string:
models.append('mn6_en')
if "MULTINET6" in models_string:
models.append('fst')
@ -116,6 +119,7 @@ if __name__ == '__main__':
sdkconfig_path = args.project_path + '/sdkconfig'
model_path = args.model_path + '/model'
target_path = args.build_path + '/srmodels'
image_file = "srmodels.bin"
if os.path.exists(target_path):
shutil.rmtree(target_path)
@ -123,6 +127,7 @@ if __name__ == '__main__':
copy_multinet_from_sdkconfig(model_path, sdkconfig_path, target_path)
copy_wakenet_from_sdkconfig(model_path, sdkconfig_path, target_path)
total_size = calculate_total_size(target_path)
pack_models(target_path, "srmodels.bin")
print("Recommended model partition size: ", str(int((total_size / 1024 + 900) / 4 ) * 4) + 'KB')
pack_models(target_path, image_file)
total_size = os.path.getsize(os.path.join(target_path, image_file))
recommended_size = int(math.ceil(total_size/1024))
print("Recommended model partition size: %dK" % (recommended_size))

View File

@ -104,7 +104,8 @@ def pack_models(model_path, out_file="srmodels.bin"):
out_bin += model_bin
assert len(out_bin) == header_len
out_bin += data_bin
if data_bin != None:
out_bin += data_bin
out_file = os.path.join(model_path, out_file)
with open(out_file, "wb") as f:

View File

@ -28,7 +28,7 @@ static srmodel_list_t* srmodel_list_alloc(void)
models->model_data = NULL;
models->model_name = NULL;
models->num = 0;
models->partition_label = NULL;
models->partition = NULL;
return models;
}
@ -247,10 +247,10 @@ srmodel_list_t *srmodel_mmap_init(const esp_partition_t *part)
const void *root;
esp_err_t err=esp_partition_mmap(part, 0, part->size, SPI_FLASH_MMAP_DATA, &root, &models->mmap_handle);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Can not map %s partition!\n", part->label);
ESP_LOGE(TAG, "Can not map %s partition!", part->label);
return NULL;
} else {
ESP_LOGI(TAG, "partition %s size: %d by mmap\n", part->label, part->size);
ESP_LOGI(TAG, "partition %s size: %d by mmap", part->label, part->size);
}
models->partition = (esp_partition_t *)part;
@ -270,7 +270,6 @@ srmodel_list_t *srmodel_mmap_init(const esp_partition_t *part)
models->model_name[i] = (char*)malloc((strlen(data)+1)*sizeof(char));
strcpy(models->model_name[i], data);
data += str_len;
printf("%s\n", models->model_name[i]);
//read model number
int file_num = read_int32(data);
model_data->num = file_num;
@ -321,6 +320,7 @@ void srmodel_mmap_deinit(srmodel_list_t *models)
free(models);
}
models = NULL;
static_srmodels = NULL;
}
#endif
@ -462,7 +462,7 @@ srmodel_list_t* esp_srmodel_init(const char* partition_label)
if (part) {
return srmodel_mmap_init(part);
} else {
ESP_LOGE(TAG, "Can not find %s in partition table\n", partition_label);
ESP_LOGE(TAG, "Can not find %s in partition table", partition_label);
}
return NULL;
@ -480,7 +480,7 @@ void esp_srmodel_deinit(srmodel_list_t *models)
#ifdef CONFIG_IDF_TARGET_ESP32
return srmodel_config_deinit(models);
#else
return srmodel_spiffs_deinit(models);
return srmodel_mmap_deinit(models);
#endif
#else

3
test/CMakeLists.txt Normal file
View File

@ -0,0 +1,3 @@
idf_component_register(SRC_DIRS "."
INCLUDE_DIRS "."
REQUIRES cmock esp-sr)

4025
test/alexa.h Normal file

File diff suppressed because it is too large Load Diff

4985
test/dakaidiandeng.h Normal file

File diff suppressed because it is too large Load Diff

7554
test/hilexin.h Normal file

File diff suppressed because it is too large Load Diff

113
test/unity_multinet.c Normal file
View File

@ -0,0 +1,113 @@
/* test_mean.c: Implementation of a testable component.
This example code is in the Public Domain (or CC0 licensed, at your option.)
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/
#include "string.h"
#include <limits.h>
#include "unity.h"
#include "model_path.h"
#include "esp_mn_iface.h"
#include "esp_mn_models.h"
#include "dakaidiandeng.h"
#include "alexa.h"
#include "dl_lib_convq_queue.h"
#include <sys/time.h>
TEST_CASE("multinet create/destroy API & memory leak", "[mn]")
{
vTaskDelay(500 / portTICK_PERIOD_MS);
int start_size = heap_caps_get_free_size(MALLOC_CAP_8BIT);
int start_internal_size = heap_caps_get_free_size(MALLOC_CAP_INTERNAL);
srmodel_list_t *models = esp_srmodel_init("model");
char *model_name = esp_srmodel_filter(models, ESP_MN_PREFIX, NULL);
esp_mn_iface_t *multinet = esp_mn_handle_from_name(model_name);
// test model loading time
struct timeval tv_start, tv_end;
gettimeofday(&tv_start, NULL);
model_iface_data_t *model_data = multinet->create(model_name, 6000);
gettimeofday(&tv_end, NULL);
int tv_ms=(tv_end.tv_sec-tv_start.tv_sec)*1000+(tv_end.tv_usec-tv_start.tv_usec)/1000;
printf("create latency:%d ms\n", tv_ms);
// test model memory concumption
int create_size = start_size - heap_caps_get_free_size(MALLOC_CAP_8BIT);
int create_internal_size = start_internal_size - heap_caps_get_free_size(MALLOC_CAP_INTERNAL);
printf("Internal RAM: %d, PSRAM:%d\n", create_internal_size, create_size-create_internal_size);
multinet->destroy(model_data);
esp_srmodel_deinit(models);
// test memory leak
int first_end_size = heap_caps_get_free_size(MALLOC_CAP_8BIT);
int first_end_internal_size = heap_caps_get_free_size(MALLOC_CAP_INTERNAL);
int last_end_size = first_end_size;
int last_end_internal_size = first_end_internal_size;
int mem_leak = start_size - last_end_size;
printf("create&destroy times:%d, memory leak:%d\n", 1, mem_leak);
for (int i=0; i<3; i++) {
printf("init partition ...\n");
models = esp_srmodel_init("model");
model_name = esp_srmodel_filter(models, ESP_MN_PREFIX, NULL);
multinet = esp_mn_handle_from_name(model_name);
printf("create ...\n");
model_data = multinet->create(model_name, 6000);
printf("destroy ...\n");
multinet->destroy(model_data);
esp_srmodel_deinit(models);
last_end_size = heap_caps_get_free_size(MALLOC_CAP_8BIT);
last_end_internal_size = heap_caps_get_free_size(MALLOC_CAP_INTERNAL);
mem_leak = start_size - last_end_size;
printf("create&destroy times:%d, memory leak:%d\n", i+2, mem_leak);
}
TEST_ASSERT_EQUAL(true, (mem_leak) < 1000 && last_end_size == first_end_size);
}
TEST_CASE("multinet detect API & cpu loading", "[mn]")
{
vTaskDelay(500 / portTICK_PERIOD_MS);
srmodel_list_t *models = esp_srmodel_init("model");
char *model_name = esp_srmodel_filter(models, ESP_MN_PREFIX, NULL);
esp_mn_iface_t *multinet = esp_mn_handle_from_name(model_name);
model_iface_data_t *model_data = multinet->create(model_name, 6000);
int frequency = multinet->get_samp_rate(model_data);
int audio_chunksize = multinet->get_samp_chunksize(model_data) * sizeof(int16_t);
int16_t *buffer = malloc(audio_chunksize);
int chunks = 0;
struct timeval tv_start, tv_end;
gettimeofday(&tv_start, NULL);
while (1) {
if ((chunks + 1)*audio_chunksize <= sizeof(alexa)) {
memcpy(buffer, alexa + chunks * audio_chunksize, audio_chunksize);
} else {
memset(buffer, 0, audio_chunksize);
}
esp_mn_state_t mn_state = multinet->detect(model_data, buffer);
chunks++;
if (chunks == 64)
break;
}
gettimeofday(&tv_end, NULL);
int tv_ms=(tv_end.tv_sec-tv_start.tv_sec)*1000+(tv_end.tv_usec-tv_start.tv_usec)/1000;
chunks -= 7;
int run_ms = (chunks)*audio_chunksize/sizeof(int16_t)*1000/frequency;
float cpu_loading = tv_ms*100.0/run_ms;
printf("Done! Took %d ms to parse %d ms worth of samples in %d iterations. CPU loading(single core):%.1f%%\n",
tv_ms, run_ms, chunks, cpu_loading);
multinet->destroy(model_data);
esp_srmodel_deinit(models);
TEST_ASSERT_EQUAL(true, (cpu_loading<75 && tv_ms>0));
}

114
test/unity_wakenet.c Normal file
View File

@ -0,0 +1,114 @@
/* test_mean.c: Implementation of a testable component.
This example code is in the Public Domain (or CC0 licensed, at your option.)
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/
#include "string.h"
#include <limits.h>
#include "unity.h"
#include "model_path.h"
#include "esp_wn_iface.h"
#include "esp_wn_models.h"
#include "hilexin.h"
#include "dl_lib_convq_queue.h"
#include <sys/time.h>
TEST_CASE("wakenet create/destroy API & memory leak", "[wn]")
{
vTaskDelay(500 / portTICK_PERIOD_MS);
int start_size = heap_caps_get_free_size(MALLOC_CAP_8BIT);
int start_internal_size = heap_caps_get_free_size(MALLOC_CAP_INTERNAL);
srmodel_list_t *models = esp_srmodel_init("model");
char *model_name = esp_srmodel_filter(models, ESP_WN_PREFIX, NULL);
esp_wn_iface_t *wakenet = esp_wn_handle_from_name(model_name);
// test model loading time
struct timeval tv_start, tv_end;
gettimeofday(&tv_start, NULL);
model_iface_data_t *model_data = wakenet->create(model_name, DET_MODE_3CH_95);
gettimeofday(&tv_end, NULL);
int tv_ms=(tv_end.tv_sec-tv_start.tv_sec)*1000+(tv_end.tv_usec-tv_start.tv_usec)/1000;
printf("create latency:%d ms\n", tv_ms);
// test model memory concumption
int create_size = start_size - heap_caps_get_free_size(MALLOC_CAP_8BIT);
int create_internal_size = start_internal_size - heap_caps_get_free_size(MALLOC_CAP_INTERNAL);
printf("Internal RAM: %d, PSRAM:%d\n", create_internal_size, create_size-create_internal_size);
wakenet->destroy(model_data);
esp_srmodel_deinit(models);
// test memory leak
int first_end_size = heap_caps_get_free_size(MALLOC_CAP_8BIT);
int first_end_internal_size = heap_caps_get_free_size(MALLOC_CAP_INTERNAL);
int last_end_size = first_end_size;
int last_end_internal_size = first_end_internal_size;
int mem_leak = start_size - last_end_size;
printf("create&destroy times:%d, memory leak:%d\n", 1, mem_leak);
for (int i=0; i<3; i++) {
printf("init partition ...\n");
models = esp_srmodel_init("model");
model_name = esp_srmodel_filter(models, ESP_WN_PREFIX, NULL);
wakenet = esp_wn_handle_from_name(model_name);
printf("create ...\n");
model_data = wakenet->create(model_name, DET_MODE_3CH_95);
printf("destroy ...\n");
wakenet->destroy(model_data);
esp_srmodel_deinit(models);
last_end_size = heap_caps_get_free_size(MALLOC_CAP_8BIT);
last_end_internal_size = heap_caps_get_free_size(MALLOC_CAP_INTERNAL);
mem_leak = start_size - last_end_size;
printf("create&destroy times:%d, memory leak:%d\n", i+2, mem_leak);
}
TEST_ASSERT_EQUAL(true, (mem_leak) < 1000 && last_end_size == first_end_size);
}
TEST_CASE("wakenet detect API & cpu loading", "[wn]")
{
vTaskDelay(500 / portTICK_PERIOD_MS);
srmodel_list_t *models = esp_srmodel_init("model");
char *model_name = esp_srmodel_filter(models, ESP_WN_PREFIX, NULL);
esp_wn_iface_t *wakenet = esp_wn_handle_from_name(model_name);
model_iface_data_t *model_data = wakenet->create(model_name, DET_MODE_95);
int frequency = wakenet->get_samp_rate(model_data);
int audio_chunksize = wakenet->get_samp_chunksize(model_data) * sizeof(int16_t);
int16_t *buffer = malloc(audio_chunksize);
int chunks = 0;
int detected = 0;
struct timeval tv_start, tv_end;
gettimeofday(&tv_start, NULL);
while (1) {
if ((chunks + 1)*audio_chunksize <= sizeof(hilexin)) {
memcpy(buffer, hilexin + chunks * audio_chunksize, audio_chunksize);
} else {
memset(buffer, 0, audio_chunksize);
}
int res = wakenet->detect(model_data, buffer);
if (res > 0)
detected = 1;
chunks++;
if (detected == 1)
break;
}
gettimeofday(&tv_end, NULL);
int tv_ms=(tv_end.tv_sec-tv_start.tv_sec)*1000+(tv_end.tv_usec-tv_start.tv_usec)/1000;
int run_ms = (chunks)*audio_chunksize/sizeof(int16_t)*1000/frequency;
float cpu_loading = tv_ms*100.0/run_ms;
printf("Done! Took %d ms to parse %d ms worth of samples in %d iterations. CPU loading(single core):%.1f%%\n",
tv_ms, run_ms, chunks, cpu_loading);
wakenet->destroy(model_data);
esp_srmodel_deinit(models);
TEST_ASSERT_EQUAL(true, (cpu_loading<75 && detected==1));
}