From 85267ee27656baffbcb488fc5b22f9b865d8ec04 Mon Sep 17 00:00:00 2001 From: iabdalkader Date: Wed, 23 May 2018 02:58:13 +0200 Subject: [PATCH] NN: Add test function. * Simulates the network without actually calling any functions. --- src/omv/nn/nn.c | 176 +++++++++++++++++++++++++++++++-------- src/omv/nn/nn.h | 1 + src/omv/py/py_nn.c | 13 ++- src/omv/py/qstrdefsomv.h | 1 + 4 files changed, 155 insertions(+), 36 deletions(-) diff --git a/src/omv/nn/nn.c b/src/omv/nn/nn.c index 570c25d9f..f04b608ee 100644 --- a/src/omv/nn/nn.c +++ b/src/omv/nn/nn.c @@ -273,19 +273,6 @@ error: return res; } -#define BUFFER_2STR(buffer)\ - (buffer == buffer1) ? "buffer1":\ - (buffer == buffer2) ? "buffer2":\ - (buffer == input_data) ? "input_data":\ - (buffer == output_data) ? "output_data": "???" - -#define CONV_FUNC_2STR(conv_func)\ - (conv_func == arm_convolve_HWC_q7_basic) ? "arm_convolve_HWC_q7_basic" :\ - (conv_func == arm_convolve_HWC_q7_fast ) ? "arm_convolve_HWC_q7_fast":"arm_convolve_HWC_q7_RGB" - -#define POOL_FUNC_2STR(pool_func)\ - (pool_func == arm_maxpool_q7_HWC) ? "arm_maxpool_q7_HWC" : "arm_avepool_q7_HWC" - int nn_run_network(nn_t *net, image_t *img, int8_t *output_data) { uint32_t layer_idx = 0; @@ -301,14 +288,14 @@ int nn_run_network(nn_t *net, image_t *img, int8_t *output_data) return -1; } - q7_t *buffer1 = fb_alloc0(net->max_scrbuf_size); - q7_t *buffer2 = buffer1 + net->max_layer_size; - q7_t *col_buffer = fb_alloc0(net->max_colbuf_size); - q7_t *input_data = NULL; q7_t *input_buffer = NULL; q7_t *output_buffer = NULL; + q7_t *buffer1 = fb_alloc0(net->max_scrbuf_size); + q7_t *buffer2 = buffer1 + net->max_layer_size; + q7_t *col_buffer = fb_alloc0(net->max_colbuf_size); + while (layer != NULL) { layer_t *prev_layer = layer->prev; @@ -347,12 +334,6 @@ int nn_run_network(nn_t *net, image_t *img, int8_t *output_data) } else { conv_func = arm_convolve_HWC_q7_fast; } - debug_printf("forward: %s(%s, %lu, %lu, %s, %lu, %lu, %lu, %lu, %s, %lu, %lu, %s, %lu, %s, %p);\n", - CONV_FUNC_2STR(conv_func), BUFFER_2STR(input_buffer), - prev_layer->h, prev_layer->c, "conv_wt", conv_layer->c, - conv_layer->krn_dim, conv_layer->krn_pad, conv_layer->krn_str, - "conv_bias", conv_layer->l_shift, conv_layer->r_shift, - BUFFER_2STR(output_buffer), conv_layer->h, "col_buffer", NULL); conv_func(input_buffer, prev_layer->h, prev_layer->c, conv_layer->wt, conv_layer->c, conv_layer->krn_dim, conv_layer->krn_pad, conv_layer->krn_str, conv_layer->bias, conv_layer->l_shift, conv_layer->r_shift, output_buffer, conv_layer->h, (q15_t*)col_buffer, NULL); @@ -361,8 +342,6 @@ int nn_run_network(nn_t *net, image_t *img, int8_t *output_data) case LAYER_TYPE_RELU: { relu_layer_t *relu_layer = (relu_layer_t *) layer; - debug_printf("forward: arm_relu_q7(%s, %lu*%lu*%lu);\n", - BUFFER_2STR(input_buffer), relu_layer->h, relu_layer->w, relu_layer->c); arm_relu_q7(input_buffer, relu_layer->h * relu_layer->w * relu_layer->c); break; } @@ -375,10 +354,6 @@ int nn_run_network(nn_t *net, image_t *img, int8_t *output_data) } else { pool_func = arm_avepool_q7_HWC; } - debug_printf("forward: %s(%s, %lu, %lu, %lu, %lu, %lu, %lu, %s, %s);\n", - POOL_FUNC_2STR(pool_func), BUFFER_2STR(input_buffer), - prev_layer->h, prev_layer->c, pool_layer->krn_dim, - pool_layer->krn_pad, pool_layer->krn_str, layer->w, "col_buffer", BUFFER_2STR(output_buffer)); pool_func(input_buffer, prev_layer->h, prev_layer->c, pool_layer->krn_dim, pool_layer->krn_pad, pool_layer->krn_str, layer->w, col_buffer, output_buffer); break; @@ -386,15 +361,150 @@ int nn_run_network(nn_t *net, image_t *img, int8_t *output_data) case LAYER_TYPE_IP: { ip_layer_t *ip_layer = (ip_layer_t*) layer; - debug_printf("forward: arm_fully_connected_q7_opt(%s, %s, %lu, %lu, %lu, %lu, %s, %s, %s);\n", - BUFFER_2STR(input_buffer), "ip_wt", prev_layer->c * prev_layer->h * prev_layer->w, - ip_layer->c, ip_layer->l_shift, ip_layer->r_shift, "ip_bias", BUFFER_2STR(output_buffer), "col_buffer"); arm_fully_connected_q7_opt(input_buffer, ip_layer->wt, prev_layer->c * prev_layer->h * prev_layer->w, ip_layer->c, ip_layer->l_shift, ip_layer->r_shift, ip_layer->bias, output_buffer, (q15_t*)col_buffer); break; } } + if (layer_idx++ > 0) { + if (input_buffer == input_data) { + // Image data has been processed + input_buffer = buffer2; + } + + if (layer->type != LAYER_TYPE_RELU) { + // Switch buffers + q7_t *tmp_buffer = input_buffer; + input_buffer = output_buffer; + output_buffer = tmp_buffer; + } + + // Last layer + if (layer->next && layer->next->next == NULL) { + output_buffer = output_data; + } + } + + layer = layer->next; + } + + fb_free_all(); + return 0; +} + +#define BUFFER_2STR(buffer)\ + (buffer == buffer1) ? "buffer1":\ + (buffer == buffer2) ? "buffer2":\ + (buffer == input_data) ? "input_data":\ + (buffer == output_data) ? "output_data": "???" + +#define CONV_FUNC_2STR(conv_func)\ + (conv_func == arm_convolve_HWC_q7_basic) ? "arm_convolve_HWC_q7_basic" :\ + (conv_func == arm_convolve_HWC_q7_fast ) ? "arm_convolve_HWC_q7_fast":"arm_convolve_HWC_q7_RGB" + +#define POOL_FUNC_2STR(pool_func)\ + (pool_func == arm_maxpool_q7_HWC) ? "arm_maxpool_q7_HWC" : "arm_avepool_q7_HWC" + +int nn_dry_run_network(nn_t *net, image_t *img, int8_t *output_data) +{ + uint32_t layer_idx = 0; + layer_t *layer = net->layers; + + if (layer == NULL) { + printf("First layer is NULL!\n"); + return -1; + } + + if (layer->type != LAYER_TYPE_DATA) { + printf("First layer is not a DATA layer!\n"); + return -1; + } + + q7_t *input_data = NULL; + q7_t *input_buffer = NULL; + q7_t *output_buffer = NULL; + + q7_t *buffer1 = fb_alloc0(net->max_scrbuf_size); + q7_t *buffer2 = buffer1 + net->max_layer_size; + + while (layer != NULL) { + layer_t *prev_layer = layer->prev; + switch (layer->type) { + case LAYER_TYPE_DATA: { + data_layer_t *data_layer = (data_layer_t *) layer; + input_data = fb_alloc(data_layer->c * data_layer->h * data_layer->w); + // Scale, convert, remove mean image and load input data. + int x_ratio = (int)((img->w<<16)/layer->w)+1; + int y_ratio = (int)((img->h<<16)/layer->h)+1; + for (int y=0, i=0; yh; y++) { + int sy = (y*y_ratio)>>16; + for (int x=0; xw; x++, i+=3) { + int sx = (x*x_ratio)>>16; + uint16_t p = IM_GET_RGB565_PIXEL(img, sx, sy); + input_data[i+0] = (int8_t) (((int) COLOR_RGB565_TO_R8(p)) - (int) data_layer->r_mean); + input_data[i+1] = (int8_t) (((int) COLOR_RGB565_TO_G8(p)) - (int) data_layer->g_mean); + input_data[i+2] = (int8_t) (((int) COLOR_RGB565_TO_B8(p)) - (int) data_layer->b_mean); + } + } + // Set image data as input buffer for the next layer. + input_buffer = input_data; + output_buffer = buffer1; + break; + } + + case LAYER_TYPE_CONV: { + conv_func_t conv_func = NULL; + conv_layer_t *conv_layer = (conv_layer_t *) layer; + if (prev_layer->c % 4 != 0 || + conv_layer->n % 2 != 0 || prev_layer->h % 2 != 0) { + conv_func = arm_convolve_HWC_q7_basic; + if (prev_layer->c == 3) { + conv_func = arm_convolve_HWC_q7_RGB; + } + } else { + conv_func = arm_convolve_HWC_q7_fast; + } + printf("forward: %s(%s, %lu, %lu, %s, %lu, %lu, %lu, %lu, %s, %lu, %lu, %s, %lu, %s, %p);\n", + CONV_FUNC_2STR(conv_func), BUFFER_2STR(input_buffer), + prev_layer->h, prev_layer->c, "conv_wt", conv_layer->c, + conv_layer->krn_dim, conv_layer->krn_pad, conv_layer->krn_str, + "conv_bias", conv_layer->l_shift, conv_layer->r_shift, + BUFFER_2STR(output_buffer), conv_layer->h, "col_buffer", NULL); + break; + } + + case LAYER_TYPE_RELU: { + relu_layer_t *relu_layer = (relu_layer_t *) layer; + printf("forward: arm_relu_q7(%s, %lu*%lu*%lu);\n", + BUFFER_2STR(input_buffer), relu_layer->h, relu_layer->w, relu_layer->c); + break; + } + + case LAYER_TYPE_POOL: { + pool_func_t pool_func = NULL; + pool_layer_t *pool_layer = (pool_layer_t *) layer; + if (pool_layer->ptype == POOL_TYPE_MAX) { + pool_func = arm_maxpool_q7_HWC; + } else { + pool_func = arm_avepool_q7_HWC; + } + printf("forward: %s(%s, %lu, %lu, %lu, %lu, %lu, %lu, %s, %s);\n", + POOL_FUNC_2STR(pool_func), BUFFER_2STR(input_buffer), + prev_layer->h, prev_layer->c, pool_layer->krn_dim, + pool_layer->krn_pad, pool_layer->krn_str, layer->w, "col_buffer", BUFFER_2STR(output_buffer)); + break; + } + + case LAYER_TYPE_IP: { + ip_layer_t *ip_layer = (ip_layer_t*) layer; + printf("forward: arm_fully_connected_q7_opt(%s, %s, %lu, %lu, %lu, %lu, %s, %s, %s);\n", + BUFFER_2STR(input_buffer), "ip_wt", prev_layer->c * prev_layer->h * prev_layer->w, + ip_layer->c, ip_layer->l_shift, ip_layer->r_shift, "ip_bias", BUFFER_2STR(output_buffer), "col_buffer"); + break; + } + } + if (layer_idx++ > 0) { if (input_buffer == input_data) { // Image data has been processed @@ -418,7 +528,7 @@ int nn_run_network(nn_t *net, image_t *img, int8_t *output_data) } fb_free_all(); - debug_printf("\n"); + printf("\n"); return 0; } #endif //IMLIB_ENABLE_CNN diff --git a/src/omv/nn/nn.h b/src/omv/nn/nn.h index efa92177b..7ab921520 100644 --- a/src/omv/nn/nn.h +++ b/src/omv/nn/nn.h @@ -98,4 +98,5 @@ typedef void (*pool_func_t)(q7_t * Im_in, const uint16_t dim_im_in, const uint16 int nn_dump_network(nn_t *net); int nn_load_network(nn_t *net, const char *path); int nn_run_network(nn_t *net, image_t *img, int8_t *output); +int nn_dry_run_network(nn_t *net, image_t *img, int8_t *output); #endif //#define __CNN_H__ diff --git a/src/omv/py/py_nn.c b/src/omv/py/py_nn.c index ceb751fd6..151491aa0 100644 --- a/src/omv/py/py_nn.c +++ b/src/omv/py/py_nn.c @@ -14,6 +14,7 @@ #include "py_helper.h" #include "py_assert.h" #include "omv_boardconfig.h" +#include static const mp_obj_type_t py_net_type; @@ -30,16 +31,22 @@ void *py_net_cobj(mp_obj_t net) STATIC mp_obj_t py_net_forward(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) { - int8_t output_data[10]; nn_t *net = py_net_cobj(args[0]); image_t *img = py_helper_arg_to_image_mutable(args[1]); - nn_run_network(net, img, output_data); + int8_t output_data[10]; //TODO alloc output buffer mp_obj_t output_list = mp_obj_new_list(0, NULL); + bool dry_run = py_helper_keyword_int(n_args, args, 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_dry_run), false); + + if (dry_run == false) { + nn_run_network(net, img, output_data); + } else { + nn_dry_run_network(net, img, output_data); + } + for (int i=0; i<10; i++) { mp_obj_list_append(output_list, mp_obj_new_int(output_data[i])); } - return output_list; } diff --git a/src/omv/py/qstrdefsomv.h b/src/omv/py/qstrdefsomv.h index f2a24ed4b..7fe2eead8 100644 --- a/src/omv/py/qstrdefsomv.h +++ b/src/omv/py/qstrdefsomv.h @@ -139,6 +139,7 @@ Q(load) // Net Q(Net) Q(forward) +Q(dry_run) // C/SIF Resolutions Q(QQCIF)