Skip to content

Latest commit

 

History

History
227 lines (180 loc) · 6.02 KB

CODE_READING.md

File metadata and controls

227 lines (180 loc) · 6.02 KB

Code reading

"Application Template", "Validation" or "System Performance" is generated by CubeMX following CubeMX components selection options.

Application template

Shape of input and output buffer (network.h)

#define AI_NETWORK_IN_NUM       (1)
#define AI_NETWORK_IN_1  \
  AI_BUFFER_OBJ_INIT(AI_BUFFER_FORMAT_FLOAT, 32, 32, 1, 1, NULL)
#define AI_NETWORK_IN_1_SIZE \
  (32 * 32 * 1)

#define AI_NETWORK_OUT_NUM      (1)
#define AI_NETWORK_OUT_1  \
  AI_BUFFER_OBJ_INIT(AI_BUFFER_FORMAT_FLOAT, 1, 1, 3, 1, NULL)
#define AI_NETWORK_OUT_1_SIZE \
  (1 * 1 * 3)

Neural network (network.c)

My neural network is defined in the source code.

Weights (network_data.c)

This is weights of the network.

ai_handle ai_network_data_weights_get(void)
{
  AI_ALIGNED(4)
  static const ai_u8 s_network_weights[ 20748 ] = {
    0x73, 0xb4, 0x29, 0x3e, 0xca, 0xe4, 0x73, 0xbe, 0xff, 0x5b,
    0x4c, 0xbe, 0x30, 0x6f, 0x8a, 0x3e, 0xcd, 0x26, 0x06, 0xbe,
    0xe6, 0x7f, 0x2c, 0xbd, 0x8c, 0x56, 0xa1, 0x3e, 0xec, 0x87,
    0xb0, 0x3d, 0xc9, 0xff, 0xa9, 0x3d, 0x07, 0x42, 0x2d, 0xbd,
    0xb6, 0xfb, 0xb3, 0x3d, 0x42, 0xf6, 0x8b, 0xbe, 0xef, 0x00,
                         :

Networks (app_x-cube-ai.c)

This is network entries definition as a constant.

static const ai_network_entry_t networks[AI_MNETWORK_NUMBER] = {
    {
        .name = (const char *)AI_NETWORK_MODEL_NAME,
        .config = AI_NETWORK_DATA_CONFIG,
        .ai_get_info = ai_network_get_info,
        .ai_create = ai_network_create,
        .ai_destroy = ai_network_destroy,
        .ai_get_error = ai_network_get_error,
        .ai_init = ai_network_init,
        .ai_run = ai_network_run,
        .ai_forward = ai_network_forward,
        .ai_data_weights_get_default = ai_network_data_weights_get,
        .params = { AI_NETWORK_DATA_WEIGHTS(0),
                AI_NETWORK_DATA_ACTIVATIONS(0)},
    },
};

Basic APIs (app_x-cube-ai.c)

In my case, *name is "network".

ai_error ai_mnetwork_create(const char *name, ai_handle* network,
        const ai_buffer* network_config);
        
ai_bool ai_mnetwork_init(ai_handle network, const ai_network_params* params);

ai_i32 ai_mnetwork_run(ai_handle network, const ai_buffer* input,
        ai_buffer* output);

Buffer format (ai_platform.h)

This is a type definition of input and output buffers. As for width and size, I just follow the definitions in network.h.

/*!
 * @struct ai_buffer
 * @ingroup ai_platform
 * @brief Memory buffer storing data (optional) with a shape, size and type.
 * This datastruct is used also for network querying, where the data field may
 * may be NULL.
 */
typedef struct ai_buffer_ {
  ai_buffer_format        format;     /*!< buffer format */
  ai_u16                  n_batches;  /*!< number of batches in the buffer */
  ai_u16                  height;     /*!< buffer height dimension */
  ai_u16                  width;      /*!< buffer width dimension */
  ai_u32                  channels;   /*!< buffer number of channels */
  ai_handle               data;       /*!< pointer to buffer data */
} ai_buffer;
/*!
 * @enum buffer formats enum list
 * @ingroup ai_platform
 *
 * List supported data buffer types.
 */
enum {
  AI_BUFFER_FORMAT_NONE     = 0x00,
  AI_BUFFER_FORMAT_FLOAT    = 0x01,
  AI_BUFFER_FORMAT_U8       = 0x10,
  AI_BUFFER_FORMAT_Q7       = 0x31, 
  AI_BUFFER_FORMAT_Q15      = 0x32,
};

How to run the network

Refer to "aiSystemPerformance.c" that is generated by selecting "System Performance" on CubeMX.

Maybe it is a good idea to use the code as a basis for developing an application. I modified the code by removing lines to make it simplest as possible, and the code became as follows (the normalization function and the probability vector should be modified depending on the use case):

#include <ai.h>
#include <bsp_ai.h>
#include "ai_platform.h"
#include "math.h"

#define AI_BUFFER_NULL(ptr_)  \
  AI_BUFFER_OBJ_INIT( \
    AI_BUFFER_FORMAT_NONE|AI_BUFFER_FMT_FLAG_CONST, \
    0, 0, 0, 0, \
    AI_HANDLE_PTR(ptr_))

static ai_u8 activations[AI_MNETWORK_DATA_ACTIVATIONS_SIZE];
ai_handle handle;
ai_network_report report;

// Standard normalization
void normalize(ai_float *in_data, ai_float *normalized_data) {

	float mean = 0.0;
	float std = 0.0;

	// Sum and mean
	for (int i = 0; i < AI_MNETWORK_IN_1_SIZE; i++) {
		mean += in_data[i];
	}
	mean = mean / AI_MNETWORK_IN_1_SIZE;

	// Standard deviation
	for (int i = 0; i < AI_MNETWORK_IN_1_SIZE; i++) {
		std += pow(in_data[i] - mean, 2);
	}
	std = sqrt(std / AI_MNETWORK_IN_1_SIZE);

	// Normalization
	for (int i = 0; i < AI_MNETWORK_IN_1_SIZE; i++) {
		normalized_data[i] = (in_data[i] - mean) / std;
	}

}

int ai_init(void) {

	ai_error err;
	const char *nn_name;
	const ai_network_params params = {
	AI_BUFFER_NULL(NULL),
	AI_BUFFER_NULL(activations) };

	// Find a network
	nn_name = ai_mnetwork_find(NULL, 0);
	if (nn_name) {
		printf("\nFound network: \"%s\"\n", nn_name);
	} else {
		printf("E: ai_mnetwork_find\n");
		return -1;
	}

	// Create the network
	err = ai_mnetwork_create(nn_name, &handle, NULL);
	if (err.type) {
		printf("E: ai_mnetwork_create\n");
		return -1;
	}

	// Initialize the network
	if (!ai_mnetwork_init(handle, &params)) {
		printf("E: ai_mnetwork_init\n");
		return -1;
	}

	return 0;
}

int ai_infer(ai_float *input_data, const char *label) {

	ai_buffer ai_input[1];
	ai_buffer ai_output[1];
	ai_float* output_;
	ai_float normalized_data[AI_MNETWORK_IN_1_SIZE];
	ai_float output_data[AI_MNETWORK_OUT_1_SIZE];

	// Normalize the input data
	normalize(input_data, normalized_data);

	ai_input[0] = report.inputs;
	ai_output[0] = report.outputs;

	ai_input[0].n_batches = 1;
	ai_input[0].data = AI_HANDLE_PTR(normalized_data);
	ai_output[0].n_batches = 1;
	ai_output[0].data = AI_HANDLE_PTR(output_data);

	ai_mnetwork_run(handle, &ai_input[0], &ai_output[0]);

	output_ = (ai_float *) (ai_output[0].data);
	printf(
		"\n--- Inference ---\n rock:        %3d%%\n paper:       %3d%%\n scissors:    %3d%%\n",
		(int) (output_[1] * 100), (int) (output_[0] * 100),
		(int) (output_[2] * 100));
	return 0;
}