From a958118bc1dc9d94e0f32d396d5b925d9c9ed05a Mon Sep 17 00:00:00 2001 From: Thibaut Vercueil Date: Thu, 24 Oct 2019 12:01:25 +0200 Subject: [PATCH] Removed Cube.AI files and added instructions to grab them --- src/stm32cubeai/AI/Inc/ai_common_config.h | 34 - src/stm32cubeai/AI/Inc/ai_datatypes_defines.h | 152 --- src/stm32cubeai/AI/Inc/ai_datatypes_format.h | 473 --------- .../AI/Inc/ai_datatypes_internal.h | 379 ------- src/stm32cubeai/AI/Inc/ai_log.h | 140 --- src/stm32cubeai/AI/Inc/ai_math_helpers.h | 301 ------ src/stm32cubeai/AI/Inc/ai_network_inspector.h | 176 ---- src/stm32cubeai/AI/Inc/ai_platform.h | 508 ---------- .../AI/Inc/ai_platform_interface.h | 786 --------------- src/stm32cubeai/AI/Inc/core_common.h | 291 ------ src/stm32cubeai/AI/Inc/core_convert.h | 72 -- src/stm32cubeai/AI/Inc/core_datatypes.h | 59 -- src/stm32cubeai/AI/Inc/core_log.h | 117 --- src/stm32cubeai/AI/Inc/core_net_inspect.h | 96 -- .../AI/Inc/core_net_inspect_interface.h | 121 --- src/stm32cubeai/AI/Inc/datatypes_network.h | 58 -- src/stm32cubeai/AI/Inc/formats_list.h | 69 -- src/stm32cubeai/AI/Inc/layers.h | 88 -- src/stm32cubeai/AI/Inc/layers_common.h | 192 ---- src/stm32cubeai/AI/Inc/layers_conv2d.h | 196 ---- src/stm32cubeai/AI/Inc/layers_dense.h | 65 -- src/stm32cubeai/AI/Inc/layers_generic.h | 371 ------- src/stm32cubeai/AI/Inc/layers_list.h | 92 -- src/stm32cubeai/AI/Inc/layers_nl.h | 925 ------------------ src/stm32cubeai/AI/Inc/layers_norm.h | 150 --- src/stm32cubeai/AI/Inc/layers_pool.h | 285 ------ src/stm32cubeai/AI/Inc/layers_rnn.h | 110 --- src/stm32cubeai/AI/Inc/layers_sm.h | 80 -- .../AI/Lib/NetworkRuntime410_CM7_GCC.a | Bin 926524 -> 0 bytes src/stm32cubeai/README.md | 25 + 30 files changed, 25 insertions(+), 6386 deletions(-) delete mode 100755 src/stm32cubeai/AI/Inc/ai_common_config.h delete mode 100755 src/stm32cubeai/AI/Inc/ai_datatypes_defines.h delete mode 100755 src/stm32cubeai/AI/Inc/ai_datatypes_format.h delete mode 100755 src/stm32cubeai/AI/Inc/ai_datatypes_internal.h delete mode 100755 src/stm32cubeai/AI/Inc/ai_log.h delete mode 100755 src/stm32cubeai/AI/Inc/ai_math_helpers.h delete mode 100755 src/stm32cubeai/AI/Inc/ai_network_inspector.h delete mode 100755 src/stm32cubeai/AI/Inc/ai_platform.h delete mode 100755 src/stm32cubeai/AI/Inc/ai_platform_interface.h delete mode 100755 src/stm32cubeai/AI/Inc/core_common.h delete mode 100755 src/stm32cubeai/AI/Inc/core_convert.h delete mode 100755 src/stm32cubeai/AI/Inc/core_datatypes.h delete mode 100755 src/stm32cubeai/AI/Inc/core_log.h delete mode 100755 src/stm32cubeai/AI/Inc/core_net_inspect.h delete mode 100755 src/stm32cubeai/AI/Inc/core_net_inspect_interface.h delete mode 100755 src/stm32cubeai/AI/Inc/datatypes_network.h delete mode 100755 src/stm32cubeai/AI/Inc/formats_list.h delete mode 100755 src/stm32cubeai/AI/Inc/layers.h delete mode 100755 src/stm32cubeai/AI/Inc/layers_common.h delete mode 100755 src/stm32cubeai/AI/Inc/layers_conv2d.h delete mode 100755 src/stm32cubeai/AI/Inc/layers_dense.h delete mode 100755 src/stm32cubeai/AI/Inc/layers_generic.h delete mode 100755 src/stm32cubeai/AI/Inc/layers_list.h delete mode 100755 src/stm32cubeai/AI/Inc/layers_nl.h delete mode 100755 src/stm32cubeai/AI/Inc/layers_norm.h delete mode 100755 src/stm32cubeai/AI/Inc/layers_pool.h delete mode 100755 src/stm32cubeai/AI/Inc/layers_rnn.h delete mode 100755 src/stm32cubeai/AI/Inc/layers_sm.h delete mode 100755 src/stm32cubeai/AI/Lib/NetworkRuntime410_CM7_GCC.a diff --git a/src/stm32cubeai/AI/Inc/ai_common_config.h b/src/stm32cubeai/AI/Inc/ai_common_config.h deleted file mode 100755 index 23ba36212..000000000 --- a/src/stm32cubeai/AI/Inc/ai_common_config.h +++ /dev/null @@ -1,34 +0,0 @@ -/** - ****************************************************************************** - * @file ai_common_config.h - * @author AST Embedded Analytics Research Platform - * @date 18-May-2018 - * @brief header file of AI platform common compile configuration defines - ****************************************************************************** - * @attention - * - *

© Copyright (c) 2018 STMicroelectronics. - * All rights reserved.

- * - * This software component is licensed by ST under Ultimate Liberty license - * SLA0044, the "License"; You may not use this file except in compliance with - * the License. You may obtain a copy of the License at: - * www.st.com/SLA0044 - * - ****************************************************************************** - */ -#ifndef __AI_COMMON_CONFIG_H_ -#define __AI_COMMON_CONFIG_H_ -#pragma once - -/*! - * @defgroup layers Layers Compilation Config Definitions - * @brief definition - * - */ - -#define HAS_PROFILE_FLOAT -#define HAS_PROFILE_FIXED - - -#endif /*__AI_COMMON_CONFIG_H_*/ diff --git a/src/stm32cubeai/AI/Inc/ai_datatypes_defines.h b/src/stm32cubeai/AI/Inc/ai_datatypes_defines.h deleted file mode 100755 index 4b2cbbdfa..000000000 --- a/src/stm32cubeai/AI/Inc/ai_datatypes_defines.h +++ /dev/null @@ -1,152 +0,0 @@ -/** - ****************************************************************************** - * @file ai_datatypes_defines.h - * @author AST Embedded Analytics Research Platform - * @date 18-Oct-2017 - * @brief Definitions of AI platform private APIs types - ****************************************************************************** - * @attention - * - *

© Copyright (c) 2017 STMicroelectronics. - * All rights reserved.

- * - * This software component is licensed by ST under Ultimate Liberty license - * SLA0044, the "License"; You may not use this file except in compliance with - * the License. You may obtain a copy of the License at: - * www.st.com/SLA0044 - * - ****************************************************************************** - */ - -#ifndef __AI_DATATYPES_DEFINES_H__ -#define __AI_DATATYPES_DEFINES_H__ -#pragma once - -#include "ai_platform.h" - -/*! - * @defgroup datatypes_defines Internal Datatypes Defines Header - * @brief Data structures used internally to implement neural networks - * - */ - -/* define to track datatypes used by codegen */ -#define AI_INTERFACE_TYPE /* AI_INTERFACE_TYPE */ - -#define AI_INTERNAL_API /* AI_INTERNAL_API */ - -#define AI_CONST const -#define AI_STATIC static -#define AI_STATIC_CONST static const - -/******************************************************************************/ -/* NOP operation used by codegen */ -#define AI_NOP /* NOP */ - -#define AI_WRAP_FUNC(fn_) do { fn_ } while (0); - -#define AI_CAT(a, ...) AI_PRIMITIVE_CAT(a, __VA_ARGS__) -#define AI_PRIMITIVE_CAT(a, ...) a ## __VA_ARGS__ - -/******************************************************************************/ -#ifdef HAS_AI_ASSERT -#include -#define AI_ASSERT(cond) \ - { assert(cond); } -#else -#define AI_ASSERT(cond) \ - AI_WRAP_FUNC(AI_NOP) -#endif /*HAS_AI_ASSERT*/ - -/******************************************************************************/ -#define AI_NO_PACKED_STRUCTS - -/* Macro for defining packed structures (compiler dependent). - * This just reduces memory requirements, but is not required. - */ -#if defined(AI_NO_PACKED_STRUCTS) - /* Disable struct packing */ - #define AI_PACKED_STRUCT_START /* AI_PACKED_STRUCT_START */ - #define AI_PACKED_STRUCT_END /* AI_PACKED_STRUCT_END */ - #define AI_PACKED /* AI_PACKED */ -#elif defined(__GNUC__) || defined(__clang__) - /* For GCC and clang */ - #define AI_PACKED_STRUCT_START /* AI_PACKED_STRUCT_START */ - #define AI_PACKED_STRUCT_END /* AI_PACKED_STRUCT_END */ - #define AI_PACKED __attribute__((packed)) -#elif defined(__ICCARM__) || defined (__IAR_SYSTEMS_ICC__) || defined(__CC_ARM) - /* For IAR ARM and Keil MDK-ARM compilers */ - #define AI_PACKED_STRUCT_START _Pragma("pack(push, 1)") - #define AI_PACKED_STRUCT_END _Pragma("pack(pop)") - #define AI_PACKED /* AI_PACKED */ -#elif defined(_MSC_VER) && (_MSC_VER >= 1500) - /* For Microsoft Visual C++ */ - #define AI_PACKED_STRUCT_START __pragma(pack(push, 1)) - #define AI_PACKED_STRUCT_END __pragma(pack(pop)) - #define AI_PACKED /* AI_PACKED */ -#else - /* Unknown compiler */ - #define AI_PACKED_STRUCT_START /* AI_PACKED_STRUCT_START */ - #define AI_PACKED_STRUCT_END /* AI_PACKED_STRUCT_END */ - #define AI_PACKED /* AI_PACKED */ -#endif /* AI_NO_PACKED_STRUCTS */ - -/******************************************************************************/ -#define AI_STRINGIFY_ARG(contents) # contents -#define AI_STRINGIFY(macro_or_string) AI_STRINGIFY_ARG (macro_or_string) - -/******************************************************************************/ -#if defined(_MSC_VER) - #define AI_DECLARE_STATIC static __inline - #define AI_ALIGNED_TYPE(type, x) type __declspec(align(x)) - #define AI_INTERFACE_ENTRY __declspec(dllexport) -#elif defined(__ICCARM__) || defined (__IAR_SYSTEMS_ICC__) - #define AI_DECLARE_STATIC static inline - #define AI_ALIGNED_TYPE(type, x) type - #define AI_INTERFACE_ENTRY /* AI_INTERFACE_ENTRY */ -#else /* _MSC_VER */ - #define AI_DECLARE_STATIC static __inline - #define AI_ALIGNED_TYPE(type, x) type __attribute__ ((aligned(x))) - #define AI_INTERFACE_ENTRY __attribute__((visibility("default"))) -#endif /* _MSC_VER */ - -/******************************************************************************/ -#define AI_ALIGN_MASKED(value, mask) ( ((value)+(mask))&(~(mask)) ) - - -#define AI_GET_REVISION(major, minor, micro) ( \ - ((ai_u32)(major)<<24) | \ - ((ai_u32)(minor)<<16) | \ - ((ai_u32)(micro)<< 8) ) - -#define AI_GET_VERSION_STRING(major, minor, micro) \ - AI_STRINGIFY_ARG(major) "." \ - AI_STRINGIFY_ARG(minor) "." \ - AI_STRINGIFY_ARG(micro) \ - -#define AI_PACK(...) \ - __VA_ARGS__ - - -#define AI_PACK_TENSORS_PTR(...) \ - AI_PACK(__VA_ARGS__) - -#define AI_PACK_INFO(size_) (ai_tensor_info[1]) { { \ - .buffer = (ai_buffer[size_])AI_STRUCT_INIT, \ - .state = (ai_tensor_state[size_])AI_STRUCT_INIT, \ -} } - -#define AI_CR "\r\n" - -#if (defined HAS_AI_DEBUG || defined HAS_DEBUG_LIB) -#define AI_DEBUG(...) __VA_ARGS__ -#else -#define AI_DEBUG(...) AI_WRAP_FUNC(AI_NOP) -#endif - -#define AI_FLAG_NONE (0x0) -#define AI_FLAG_SET(mask, flag) (mask) |= (flag) -#define AI_FLAG_UNSET(mask, flag) (mask) &= (~(flag)) -#define AI_FLAG_IS_SET(mask, flag) ( (flag)==((mask)&(flag)) ) - -#endif /*__AI_DATATYPES_DEFINES_H__*/ diff --git a/src/stm32cubeai/AI/Inc/ai_datatypes_format.h b/src/stm32cubeai/AI/Inc/ai_datatypes_format.h deleted file mode 100755 index 5676bfa99..000000000 --- a/src/stm32cubeai/AI/Inc/ai_datatypes_format.h +++ /dev/null @@ -1,473 +0,0 @@ -/** - ****************************************************************************** - * @file ai_datatypes_format.h - * @author AST Embedded Analytics Research Platform - * @date 18-Oct-2017 - * @brief Definitions of AI platform private format handling routines - ****************************************************************************** - * @attention - * - *

© Copyright (c) 2017 STMicroelectronics. - * All rights reserved.

- * - * This software component is licensed by ST under Ultimate Liberty license - * SLA0044, the "License"; You may not use this file except in compliance with - * the License. You may obtain a copy of the License at: - * www.st.com/SLA0044 - * - ****************************************************************************** - */ - -#ifndef __AI_DATATYPES_FORMAT_H__ -#define __AI_DATATYPES_FORMAT_H__ -#pragma once - -#include "ai_platform.h" -#include "ai_datatypes_defines.h" - -#include "core_datatypes.h" - -/*! - * @defgroup ai_datatypes_format Definiton and Macro of array and buffer formats - * @brief Type definition and implementation of internal @ref ai_array and - * @ref ai_buffer formats. - * @details The library handles 2 different kind of formats: an internal format - * that is part of the @ref ai_array struct that is a packed 32bit representation - * of the format attributes, and a public format (used in public APIs) associated - * with @ref ai_buffer struct , defined as enum in @ref ai_platform.h, - * that is just an enum type. Converters are provided in this header file to - * convert from one format representation to another. - * Some MSB bits are reserved in both formats to code some bit flag useful to - * declare some special attribute. Three flags are actually implemented in both - * formats: the @ref AI_BUFFER_FMT_FLAG_CONST and @ref AI_FMT_FLAG_CONST used - * to tag read-only memory buffers, @ref AI_BUFFER_FMT_FLAG_STATIC and - * @ref AI_FMT_FLAG_STATIC to mark statically allocated memory buffers and - * @ref AI_FMT_FLAG_SCRATCH_BUFFER to tag temporary scratch buffers. - * All the formats are declared in a proper tuple organize table header named - * @ref format_lists.h that enumerates all the formats available for the library. - * A new format could be added easily by adding a new FMY_ENTRY() as required. - * The preprocessor automatically generates the code for the handling of the - * format according to this tuples entry. A rational for the methodology could - * be found here: - * - https://codecraft.co/2012/10/29/how-enums-spread-disease-and-how-to-cure-it/ - * - * The 32bits internal format fields are organized as follows: - * - * MSB LSB - * 31 25 24 23 21 17 14 7 0 - * /---------------------------------------------------------------------------/ - * / ATTR. FLAGS | FLOAT | SIGN | LDIV | TYPE | PBITS | BITS | FBITS / - * /---------------------------------------------------------------------------/ - * Where: - * - FLAGS: is the reserved bits to store additional format attributes (e.g. - * I/O / STATIC flags. etc.) - * - FLOAT: 1 bit mark the format as floating point type - * - SIGN : 1 bit mark the format as signed type - * - LDIV : 2 bits is a log2 value that is used to compute elements size - * with some special format such as the compressed ones. It is a shift - * factor usually set to zero - * - TYPE : 4 bits mark the format "family" type. Actually 5 families are coded, - * @ref AI_FMT_FLOAT (float types) - * @ref AI_FMT_Q (fixed-point types in Qm.n format) - * @ref AI_FMT_LUT4 (compressed lookup 16 formats) - * @ref AI_FMT_LUT8 (compressed lookup 256 formats) - * - PBITS 3 bits padding bits used to set the number of padding bits - * (per element) to handle special aligned formats/ E.g. a 6 bit format - * where each element is stored byte aligned (8 bits) has 2 padding bits. - * Usually this is set to 0 - * - BITS 7 bits set the total number of bits of the element, padding bits - * excluded. The bits are thus = sign bit + fractional bits + integer bits - * The number of integer bits could thus be known using the @ref - * AI_FMT_GET_IBITS() macro. - * - FBITS 7 bits set the number of fractional bits in the format - * - * - * A reference code snippet for usage is the test unit that uses this header: - * - * \include test/test_lcut_formats.cpp - * - */ - -/*! - * Format bitfields definition. NOTE: 7 MSB are masked off - * for (optional) atributes setting using flags. see @ref AI_FMT_FLAG_CONST that - * is used for marking a data as constant readonly - */ - -/* 1 bit field to identify floating point values*/ -#define _FMT_FLOAT_MASK (0x1) -#define _FMT_FLOAT_BITS (24) - -/*! 1 bit sign info */ -#define _FMT_SIGN_MASK (0x1) -#define _FMT_SIGN_BITS (23) - -/*! fractional bits field (i.e. for Q formats see @ref AI_FMT_Q) */ -#define _FMT_FBITS_MASK (0x7F) -#define _FMT_FBITS_BITS (0) -#define _FMT_FBITS_BIAS ((_FMT_FBITS_MASK+1) >> 1) - -/*! TOTAL number of bits (fractional+integer+sign) (excluded padding ones) */ -#define _FMT_BITS_MASK (0x7F) -#define _FMT_BITS_BITS (7) -#define _FMT_BITS_BIAS (0) - -/*! Padding bits for handling formats not aligned to multiples of 8 bits */ -#define _FMT_PBITS_MASK (0x7) -#define _FMT_PBITS_BITS (14) - -/*! bits reserved for identifying the family format, e.g. float, fixed-point..*/ -#define _FMT_TYPE_MASK (0xF) -#define _FMT_TYPE_BITS (17) - -#define _FMT_LDIV_MASK (0x3) -#define _FMT_LDIV_BITS (21) - - -/******************************************************************************/ -#define AI_FMT_OBJ(fmt_) ((ai_array_format)(fmt_)) - -/*! - * Only 25 LSB bits are used for storing actual format bits. 7 bits are reserved - * for format attributes, see @ref AI_FMT_FLAG_CONST flag - */ -#define AI_FMT_FLAG_BITS (25) -#define AI_FMT_MASK ((0x1<> AI_FMT_FLAG_BITS ) - -#define AI_FMT_SAME(fmt1_, fmt2_) \ - ( AI_FMT_GET(fmt1_) == AI_FMT_GET(fmt2_) ) - -#define _FMT_SET(val, mask, bits) AI_FMT_OBJ(((val)&(mask))<<(bits)) -#define _FMT_GET(fmt, mask, bits) ((AI_FMT_OBJ(fmt)>>(bits))&(mask)) - -#define AI_FMT_SET_FLOAT(val) _FMT_SET(val, _FMT_FLOAT_MASK, _FMT_FLOAT_BITS) -#define AI_FMT_GET_FLOAT(fmt) _FMT_GET(fmt, _FMT_FLOAT_MASK, _FMT_FLOAT_BITS) -#define AI_FMT_SET_SIGN(val) _FMT_SET(val, _FMT_SIGN_MASK, _FMT_SIGN_BITS) -#define AI_FMT_GET_SIGN(fmt) _FMT_GET(fmt, _FMT_SIGN_MASK, _FMT_SIGN_BITS) -#define AI_FMT_SET_PBITS(val) _FMT_SET(val, _FMT_PBITS_MASK, _FMT_PBITS_BITS) -#define AI_FMT_GET_PBITS(fmt) _FMT_GET(fmt, _FMT_PBITS_MASK, _FMT_PBITS_BITS) -#define AI_FMT_SET_TYPE(val) _FMT_SET(val, _FMT_TYPE_MASK, _FMT_TYPE_BITS) -#define AI_FMT_GET_TYPE(fmt) _FMT_GET(fmt, _FMT_TYPE_MASK, _FMT_TYPE_BITS) -#define AI_FMT_SET_LDIV(val) _FMT_SET(val, _FMT_LDIV_MASK, _FMT_LDIV_BITS) -#define AI_FMT_GET_LDIV(fmt) _FMT_GET(fmt, _FMT_LDIV_MASK, _FMT_LDIV_BITS) - -#define AI_FMT_SET_BITS(val) \ - _FMT_SET((val) + _FMT_BITS_BIAS, _FMT_BITS_MASK, _FMT_BITS_BITS) -#define AI_FMT_GET_BITS(fmt) \ - ((ai_i8)_FMT_GET(fmt, _FMT_BITS_MASK, _FMT_BITS_BITS) - _FMT_BITS_BIAS) -#define AI_FMT_SET_FBITS(val) \ - _FMT_SET((val) + _FMT_FBITS_BIAS, _FMT_FBITS_MASK, _FMT_FBITS_BITS) -#define AI_FMT_GET_FBITS(fmt) \ - ((ai_i8)_FMT_GET(fmt, _FMT_FBITS_MASK, _FMT_FBITS_BITS) - _FMT_FBITS_BIAS) - -/*! - * The total number of bits for a given format is supposed to be the sum of the - * bits + padding bits. This means that the number of integer bits is derived - * as follow: int_bits = bits - fbits (fractional bits) - 1 (for the sign) - */ -#define AI_FMT_GET_BITS_SIZE(fmt_) \ - (AI_FMT_GET_BITS(fmt_)+AI_FMT_GET_PBITS(fmt_)) - -/*! Macro used to compute the integer bits for a format */ -#define AI_FMT_GET_IBITS(fmt_) \ - ((ai_i16)AI_FMT_GET_BITS(fmt_)-AI_FMT_GET_FBITS(fmt_)-AI_FMT_GET_SIGN(fmt_)) - -/*! ai_buffer format handlers section *****************************************/ - -#define AI_BUFFER_FMT_MASK_Q(fmt_) \ - ( AI_BUFFER_FMT_OBJ(fmt_) & 0xFFFFC000 ) - -#define AI_BUFFER_FMT_GET_Q(fmt_) \ - ( AI_BUFFER_FMT_MASK_Q(fmt_) | AI_BUFFER_FMT_SET_FBITS(0) | \ - AI_BUFFER_FMT_SET_FBITS(0) ) - -#define AI_BUFFER_FMT_SET_Q(bits_, fbits_) \ - AI_BUFFER_FMT_SET(AI_BUFFER_FMT_TYPE_Q, 1, 0, bits_, fbits_) - -#define AI_BUFFER_FMT_IS_Q(fmt_) \ - ( (AI_BUFFER_FMT_TYPE_Q==AI_BUFFER_FMT_GET_TYPE(fmt_)) && \ - (1==AI_BUFFER_FMT_GET_SIGN(fmt_)) ) - -#define AI_BUFFER_FMT_SET_UQ(bits_, fbits_) \ - AI_BUFFER_FMT_SET(AI_BUFFER_FMT_TYPE_Q, 0, 0, bits_, fbits_) - -#define AI_BUFFER_FMT_IS_UQ(fmt_) \ - ( (AI_BUFFER_FMT_TYPE_Q==AI_BUFFER_FMT_GET_TYPE(fmt_)) && \ - (0==AI_BUFFER_FMT_GET_SIGN(fmt_)) ) - -/*! Q ai_array format handlers ************************************************/ -#define AI_ARRAY_FMT_SET_Q(bits_, fbits_) \ - ( AI_FMT_MASK_Q(AI_ARRAY_FORMAT_Q) | AI_FMT_SET_BITS(bits_) | AI_FMT_SET_FBITS(fbits_) ) - -#define AI_ARRAY_FMT_IS_Q(fmt_) \ - ( AI_FMT_GET(AI_FMT_MASK_Q(AI_ARRAY_FORMAT_Q))==AI_FMT_GET(AI_FMT_MASK_Q(fmt_)) ) - -#define AI_ARRAY_FMT_SET_UQ(bits_, fbits_) \ - ( AI_FMT_MASK_Q(AI_ARRAY_FORMAT_UQ) | AI_FMT_SET_BITS(bits_) | AI_FMT_SET_FBITS(fbits_) ) - -#define AI_ARRAY_FMT_IS_UQ(fmt_) \ - ( AI_FMT_GET(AI_FMT_MASK_Q(AI_ARRAY_FORMAT_UQ))==AI_FMT_GET(AI_FMT_MASK_Q(fmt_)) ) - -AI_DEPRECATED -/* Alias for AI_ARRAY_FMT_SET_Q */ -#define AI_ARRAY_FMT_SET_SQ(bits_, fbits_) \ - AI_ARRAY_FMT_SET_Q(bits_, fbits_) - -AI_DEPRECATED -/* Alias for AI_ARRAY_FMT_IS_Q */ -#define AI_ARRAY_FMT_IS_SQ(fmt_) \ - AI_ARRAY_FMT_IS_Q(fmt_) - -/*! ai_array section **********************************************************/ -#define AI_ARRAY_FMT_ENTRY(name_) \ - AI_CONCAT(AI_ARRAY_FORMAT_, name_) - -#define AI_ARRAY_FMT_NAME(fmt_) \ - ai_array_fmt_name(fmt_) - -#define AI_ARRAY_FMT_VALID(fmt_) \ - ai_array_fmt_valid(fmt_) - -#define AI_ARRAY_FMT_EXPORTED(fmt_) \ - ai_array_fmt_exported(fmt_) - -#define AI_ARRAY_FMT_GET_FORMATS(formats_) \ - ai_array_fmt_get_formats(formats_) - -#define AI_ARRAY_TO_BUFFER_FMT(fmt_) \ - ai_array_to_buffer_fmt(fmt_) - -#define AI_ARRAY_GET_BYTE_SIZE(fmt_, count_) \ - ai_array_get_byte_size(fmt_, count_) - -#define AI_ARRAY_GET_DATA_BYTE_SIZE(fmt_, count_) \ - ai_array_get_data_byte_size(fmt_, count_) - -#define AI_ARRAY_GET_ELEMS_FROM_SIZE(fmt_, size_) \ - ai_array_get_elems_from_size(fmt_, size_) - - -AI_API_DECLARE_BEGIN - -/*! - * @typedef ai_array_format - * @ingroup ai_datatypes_format - * @brief Generic Data Format Specifier for @ref ai_array (32bits packed info) - */ -typedef int32_t ai_array_format; - -/*! - * @enum internal data format enums - * @ingroup ai_datatypes_format - * @brief Generic Data Format Specifier (32bits packed info) - */ -typedef enum { -#define FMT_ENTRY(exp_, name_, type_id_, sign_bit_, float_bit_, \ - pbits_, bits_, fbits_, ldiv_bits_) \ - AI_ARRAY_FMT_ENTRY(name_) = (AI_FMT_SET_FLOAT(float_bit_) | \ - AI_FMT_SET_SIGN(sign_bit_) | \ - AI_FMT_SET_BITS(bits_) | \ - AI_FMT_SET_FBITS(fbits_) | \ - AI_FMT_SET_PBITS(pbits_) | \ - AI_FMT_SET_TYPE(type_id_) | \ - AI_FMT_SET_LDIV(ldiv_bits_)), -#include "formats_list.h" -} ai_array_format_entry; - -/*! - * @brief Get a human readable string from the format ID value - * @ingroup ai_datatypes_format - * @param[in] type the @ref ai_array_format to print out - * @return a string with a human readable name of the format - */ -AI_INTERNAL_API -const char* ai_array_fmt_name(const ai_array_format type); - -/*! - * @brief Check if @ref ai_array_format is a exportable to an @ref ai_buffer_format - * @ingroup ai_datatypes_format - * @param[in] type the ai_array_format to check - * @return true if the format is exported, false otherwise - */ -AI_INTERNAL_API -ai_bool ai_array_fmt_exported(const ai_array_format type); - -/*! - * @brief Check if @ref ai_array_format is a valid format present in the list of - * supported formats - * @ingroup ai_datatypes_format - * @param[in] type the ai_array_format to check - * @return true if the format is valid, false otherwise - */ -AI_INTERNAL_API -ai_bool ai_array_fmt_valid(const ai_array_format type); - -/*! - * @brief Get the complete list of supported @ref ai_array_format formats - * @ingroup ai_datatypes_format - * @param[out] formats a pointer to an array withj all supported formats listed - * @return the number of supported formats - */ -AI_INTERNAL_API -ai_size ai_array_fmt_get_formats(const ai_array_format** formats); - -/*! ai_buffer section ********************************************************* - * Only 25 LSB bits are used for storing actual format bits. 7 bits are reserved - * for format atrtributes, see @ref AI_FMT_FLAG_CONST flag - */ - -#define AI_BUFFER_FMT_ENTRY(name_) \ - AI_CONCAT(AI_BUFFER_FORMAT_, name_) - -#define AI_BUFFER_FMT_NAME(type_) \ - ai_buffer_fmt_name(type_) - -#define AI_BUFFER_FMT_VALID(type_) \ - ai_buffer_fmt_valid(type_) - -#define AI_BUFFER_FMT_GET_FORMATS(formats_) \ - ai_buffer_fmt_get_formats(formats_) - -#define AI_BUFFER_TO_ARRAY_FMT(fmt_) \ - ai_buffer_to_array_fmt(fmt_) - -#define AI_BUFFER_GET_BITS_SIZE(fmt) \ - AI_ARRAY_GET_BITS_SIZE(AI_BUFFER_TO_ARRAY_FMT(fmt)) - - -/*! - * @brief Get a human readable string from the format ID value - * @ingroup ai_datatypes_format - * @param[in] type the @ref ai_buffer_format to print out - * @return a string with a human readable name of the format - */ -AI_INTERNAL_API -const char* ai_buffer_fmt_name( - const ai_buffer_format type); - -/*! - * @brief Check if @ref ai_buffer_format is a valid format present in the list - * of supported formats - * @ingroup ai_datatypes_format - * @param[in] type the @ref ai_buffer_format to check - * @return true if the format is valid, false otherwise - */ -AI_INTERNAL_API -ai_bool ai_buffer_fmt_valid( - const ai_buffer_format type); - -/*! - * @brief Get the complete list of supported @ref ai_buffer_format formats - * @ingroup ai_datatypes_format - * @param[out] formats a pointer to an array with all supported formats listed - * @return the number of supported formats - */ -AI_INTERNAL_API -ai_size ai_buffer_fmt_get_formats( - const ai_buffer_format** formats); - -/*! Conversions section *******************************************************/ -/*! - * @brief Convert from ai_array_format to ai_buffer_format. - * @ingroup ai_datatypes_format - * @param fmt the input ai_array_format to convert - * @return the converted format as a ai_buffer_format - */ -AI_INTERNAL_API -ai_buffer_format ai_array_to_buffer_fmt( - const ai_array_format fmt); - -/*! - * @brief Convert from ai_buffer_format to ai_array_format. - * @ingroup ai_datatypes_format - * @param fmt the input ai_buffer_format to convert - * @return the converted format as a ai_array_format - */ -AI_INTERNAL_API -ai_array_format ai_buffer_to_array_fmt( - const ai_buffer_format fmt); - -/** helpers section ***********************************************************/ -/*! - * @brief Computes the size in bytes given an ai_array_format and number of - * array elements. - * @details This routine computes from the number of elements of the array its - * size in bytes. If the array is referred by a tensor structure, it is the task - * of the latter to handle per-dimension padding (e.g. to align odd rows in a - * 4-bit matrix. At array level the padding elements MUST be included in the - * number of elements. - * @ingroup ai_datatypes_format - * @param[in] fmt the input array format as an ai_array_format - * @param[in] count the number of elements stored in the data array - * @return the size in bytes of the array given the specific format and number - * of elements (including padding elements) - */ -AI_INTERNAL_API -ai_size ai_array_get_byte_size( - const ai_array_format fmt, const ai_size count); - -/*! - * @brief Computes the size in bytes given an ai_array_format and number of - * array elements of the data fields (e.g. LUT table size excluded). - * @details This routine computes from the number of elements of the array its - * size in bytes. If the array is referred by a tensor structure, it is the task - * of the latter to handle per-dimension padding (e.g. to align odd rows in a - * 4-bit matrix. At array level the padding elements MUST be included in the - * number of elements. - * @ingroup ai_datatypes_format - * @param[in] fmt the input array format as an ai_array_format - * @param[in] count the number of elements stored in the data array - * @return the size in bytes of the array given the specific format and number - * of elements (including padding elements) - */ -AI_INTERNAL_API -ai_size ai_array_get_data_byte_size( - const ai_array_format fmt, const ai_size count); - -/*! - * @brief Computes the number of elements from ai_array_format and - * the size in byte of the array. - * @ingroup ai_datatypes_format - * @param fmt the input array format as an ai_array_format - * @param size the size in bytes of the array - * @return the number of elements that could be stored given the format - */ -AI_INTERNAL_API -ai_size ai_array_get_elems_from_size( - const ai_array_format fmt, const ai_size byte_size); - -AI_API_DECLARE_END - -#endif /*__AI_DATATYPES_FORMAT_H__*/ diff --git a/src/stm32cubeai/AI/Inc/ai_datatypes_internal.h b/src/stm32cubeai/AI/Inc/ai_datatypes_internal.h deleted file mode 100755 index b19a10602..000000000 --- a/src/stm32cubeai/AI/Inc/ai_datatypes_internal.h +++ /dev/null @@ -1,379 +0,0 @@ -/** - ****************************************************************************** - * @file ai_datatypes_internal.h - * @author AST Embedded Analytics Research Platform - * @date 01-May-2017 - * @brief Definitions of AI platform private APIs types - ****************************************************************************** - * @attention - * - *

© Copyright (c) 2017 STMicroelectronics. - * All rights reserved.

- * - * This software component is licensed by ST under Ultimate Liberty license - * SLA0044, the "License"; You may not use this file except in compliance with - * the License. You may obtain a copy of the License at: - * www.st.com/SLA0044 - * - ****************************************************************************** - */ - -#ifndef __AI_DATATYPES_INTERNAL_H__ -#define __AI_DATATYPES_INTERNAL_H__ -#pragma once - -#include -#include "ai_platform.h" -#include "ai_platform_interface.h" - - -/*! - * @defgroup datatypes_internal Internal Datatypes - * @brief Data structures used internally to implement neural networks - * - * The layers are defined as structs; a generic layer type defines the basic - * layer parameters and type-specific parameters are handled by specializations - * implemented as a C union. The layers keep also a pointer to the parent - * network and the next layer in the network. - * The input, output and parameters are tensor with an hard-coded maximum - * dimension of 4. Tensors are floating point arrays with a notion of size. - * The network is a linked list of layers, and thus it stores only the pointer - * to the first layer. - */ - -/*! - * @section Offsets - * @ingroup datatypes_internal - * Macros to handle (byte) stride addressing on tensors. The `AI_PTR` macro - * is used to always cast a pointer to byte array. The macros `AI_OFFSET_X` are - * used to compute (byte) offsets of respectively adjacents row elements, col - * elements, channel elements and `channel_in` elements. - * @{ - */ - -/** Count Variable Number of Arguments (up to 64 elements) ********************/ -#define AI_NUMARGS(...) \ - PP_NARG_(__VA_ARGS__,PP_RSEQ_N()) -#define PP_NARG_(...) \ - PP_ARG_N(__VA_ARGS__) -#define PP_ARG_N( \ - _1, _2, _3, _4, _5, _6, _7, _8, _9,_10, \ - _11,_12,_13,_14,_15,_16,_17,_18,_19,_20, \ - _21,_22,_23,_24,_25,_26,_27,_28,_29,_30, \ - _31,_32,_33,_34,_35,_36,_37,_38,_39,_40, \ - _41,_42,_43,_44,_45,_46,_47,_48,_49,_50, \ - _51,_52,_53,_54,_55,_56,_57,_58,_59,_60, \ - _61,_62,_63,N,...) N -#define PP_RSEQ_N() \ - 63,62,61,60, \ - 59,58,57,56,55,54,53,52,51,50, \ - 49,48,47,46,45,44,43,42,41,40, \ - 39,38,37,36,35,34,33,32,31,30, \ - 29,28,27,26,25,24,23,22,21,20, \ - 19,18,17,16,15,14,13,12,11,10, \ - 9,8,7,6,5,4,3,2,1,0 - -#define AI_PTR_ALIGN(ptr, alignment) \ - ( (((ai_uptr)(ptr))+((ai_uptr)(alignment)-1))&(~((ai_uptr)(alignment)-1)) ) - - -/*! AI_STORAGE_KLASS SECTION ************************************/ -#define AI_STORAGE_KLASS_TYPE(s_) \ - ( (s_)->type ) - -#define AI_STORAGE_KLASS_SIZE(s_) \ - ( (s_)->size ) - -#define AI_STORAGE_KLASS_DATA(s_, type_) \ - ( (type_*)((s_)->data) ) - -#define AI_STORAGE_KLASS_COPY(dst_, dst_type_, src_, src_type_) \ -{ \ - AI_ASSERT(AI_STORAGE_KLASS_SIZE(src_)>=AI_STORAGE_KLASS_SIZE(dst_)) \ - AI_STORAGE_KLASS_SIZE(dst_) = AI_STORAGE_KLASS_SIZE(src_); \ - for (ai_size i=0; iklass : NULL ) - -#define AI_TENSOR_SHAPE(tensor_) \ - ( &((tensor_)->shape) ) - -#define AI_TENSOR_STRIDE(tensor_) \ - ( &((tensor_)->stride) ) - -#define AI_TENSOR_INFO(tensor_) \ - ( &((tensor_)->info) ) - -#define AI_TENSOR_DATA(tensor_) \ - ( (tensor_) ? (tensor_)->data : NULL ) - -#define AI_TENSOR_ID(tensor_) \ - ( (tensor_) ? AI_TENSOR_INFO(tensor_)->id : 0 ) - -#define AI_TENSOR_FLAGS(tensor_) \ - ( (tensor_) ? AI_TENSOR_INFO(tensor_)->flags : 0 ) - - -#define AI_TENSOR_DATA_SIZE(tensor_) \ - ( (tensor_) ? AI_TENSOR_INFO(tensor_)->data_size : 0 ) - -/*! AI_OFFSETS SECTION ***********************************/ -//#define AI_OFFSET_BATCH(b, stride) ((ai_ptr_offset)(b) * AI_STRIDE_BATCH(stride)) -#define AI_OFFSET_H(y, stride) ((ai_ptr_offset)(y) * AI_STRIDE_H(stride)) -#define AI_OFFSET_W(x, stride) ((ai_ptr_offset)(x) * AI_STRIDE_W(stride)) -#define AI_OFFSET_CH(ch, stride) ((ai_ptr_offset)(ch) * AI_STRIDE_CH(stride)) -#define AI_OFFSET_IN_CH(ch, stride) ((ai_ptr_offset)(ch) * \ - AI_STRIDE_IN_CH(stride)) -#define AI_OFFSET(y, x, ch, in_ch, stride) ( \ - AI_OFFSET_H((y), (stride)) + AI_OFFSET_W((x), (stride)) + \ - AI_OFFSET_CH((ch), (stride)) + AI_OFFSET_IN_CH((in_ch), (stride)) ) - -/*! @} */ - -#define AI_GET_CONV_OUT_SIZE(in_size, filt_size, pad_l, pad_r, filt_stride) \ - ((((in_size) - (filt_size) + (pad_l) + (pad_r)) / (filt_stride)) + 1) - - -/** Tensors datatypes defines handlers ****************************************/ -#define AI_TENSOR_SIZE(tensor_) \ - ( AI_SHAPE_H(AI_TENSOR_SHAPE(tensor_)) * AI_SHAPE_W(AI_TENSOR_SHAPE(tensor_)) * \ - AI_SHAPE_CH(AI_TENSOR_SHAPE(tensor_)) * AI_SHAPE_IN_CH(AI_TENSOR_SHAPE(tensor_)) ) - -#define AI_TENSOR_BYTE_SIZE(tensor_) \ - ( AI_SHAPE_H(AI_TENSOR_SHAPE(tensor_)) * AI_STRIDE_H(AI_TENSOR_STRIDE(tensor_)) ) - -/******************************************************************************/ - -/** Integer tensor info extraction ********************************************/ -#define AI_INTQ_INFO_LIST_SCALE_ARRAY(list_, type_) \ - ( ((list_) && (list_)->info) \ - ? ((type_*)((list_)->info->scale)) : NULL ) - -#define AI_INTQ_INFO_LIST_ZEROPOINT_ARRAY(list_, type_) \ - ( ((list_) && (list_)->info) \ - ? ((type_*)((list_)->info->zeropoint)) : NULL ) - -#define AI_KLASS_GET_INTQ_INFO_LIST(tensor_) \ - ((ai_intq_info_list*)((tensor_)->klass)) - - -AI_API_DECLARE_BEGIN - -/*! - * @typedef ai_offset - * @ingroup ai_datatypes_internal - * @brief Generic index offset type - */ -typedef int32_t ai_offset; - - -/*! - * @typedef ai_vec4_float - * @ingroup ai_datatypes_internal - * @brief 32bit X 4 float (optimization for embedded MCU) - */ -typedef struct _ai_vec4_float { - ai_float a1; - ai_float a2; - ai_float a3; - ai_float a4; -} ai_vec4_float; - - -#define AI_VEC4_FLOAT(ptr_) \ - _get_vec4_float((ai_handle)(ptr_)) - -AI_DECLARE_STATIC -ai_vec4_float _get_vec4_float(const ai_handle fptr) -{ - return *((const ai_vec4_float*)fptr); -} - -/*! - * @typedef (*func_copy_tensor) - * @ingroup datatypes_internal - * @brief Fuction pointer for generic tensor copy routines - * this function pointer abstracts a generic tensor copy routine. - */ -typedef ai_bool (*func_copy_tensor)(ai_tensor* dst, const ai_tensor* src); - - -/*! - * @brief Check whether 2 shapes have identical dimensions. - * @ingroup datatypes_internal - * @param shape0 the 1st tensor shape to compare - * @param shape1 the 2nd tensor shape to compare - * @return true if shape0 and shape1 have same dimensions. false otherwise - */ -AI_DECLARE_STATIC -ai_bool ai_shape_is_same( - const ai_shape* shape0, const ai_shape* shape1) -{ - AI_ASSERT(shape0 && shape1) - AI_ASSERT(AI_SHAPE_SIZE(shape0)==AI_SHAPE_SIZE(shape1)) - ai_size dim = AI_SHAPE_SIZE(shape0); - while ( dim>0 ) { - dim--; - if ( AI_SHAPE_ELEM(shape0, dim)!=AI_SHAPE_ELEM(shape1, dim) ) - return false; - } - return true; -} - -/*! - * @brief Check if shape0 is a subshape of shape1 - * @ingroup datatypes_internal - * @param shape0 the 1st tensor shape to compare - * @param shape1 the 2nd tensor shape to compare - * @return true if shape0 is a subshape of shape1 (all shape0 dimensions are -* smallers or equal of the shape1 ones). false otherwise - */ -AI_DECLARE_STATIC -ai_bool ai_shape_is_subshape( - const ai_shape* shape0, const ai_shape* shape1) -{ - AI_ASSERT(shape0 && shape1) - AI_ASSERT(AI_SHAPE_SIZE(shape0)==AI_SHAPE_SIZE(shape1)) - ai_size dim = AI_SHAPE_SIZE(shape0); - while ( dim ) { - dim--; - if ( AI_SHAPE_ELEM(shape0, dim)>AI_SHAPE_ELEM(shape1, dim) ) - return false; - } - return true; -} - -/*! - * @brief Computes the total size of a tensor given its dimensions. - * @ingroup datatypes_internal - * @param shape the tensor shape - */ -AI_DECLARE_STATIC -ai_size ai_shape_get_size(const ai_shape* shape) -{ - AI_ASSERT(shape) - AI_ASSERT(AI_SHAPE_SIZE(shape)==AI_SHAPE_MAX_DIMENSION) - ai_size dim = AI_SHAPE_SIZE(shape); - ai_size size = 1; - while ( dim>0 ) { - dim--; - size *= AI_SHAPE_ELEM(shape, dim); - } - return size; -} - -/*! - * @brief Computes the size of the input image discarding the channels. - * @ingroup datatypes_internal - * @param shape the tensor shape - */ -AI_DECLARE_STATIC -ai_size ai_shape_get_npixels(const ai_shape* shape) -{ - AI_ASSERT(shape) - const ai_size npixels = AI_SHAPE_W(shape) * AI_SHAPE_H(shape); - return npixels; -} - -/*! - * @brief Map from ai_buffer data struct to ai_array data struct. - * @ingroup datatypes_internal - * @param buf a pointer to the ai_buffer to be mapped to ai_array - * @return an initialized @ref ai_array struct representing same data - */ -AI_DECLARE_STATIC -ai_array ai_from_buffer_to_array(const ai_buffer* buf) -{ - AI_ASSERT(buf) - const ai_u32 size = AI_BUFFER_SIZE(buf) * buf->n_batches; - - AI_ARRAY_OBJ_DECLARE(a, AI_BUFFER_TO_ARRAY_FMT(AI_BUFFER_FMT_OBJ(buf->format)), - buf->data, buf->data, size, AI_CONST); - return a; -} - -/*! - * @brief Map from ai_array data struct to ai_buffer data struct. - * @ingroup datatypes_internal - * @param array a pointer to the ai_array to be mapped to ai_buffer - * @return an initialized @ref ai_buffer struct representing same data - */ -AI_DECLARE_STATIC -ai_buffer ai_from_array_to_buffer(const ai_array* array) -{ - AI_ASSERT(array) - const ai_buffer b = AI_BUFFER_OBJ_INIT(AI_ARRAY_TO_BUFFER_FMT(array->format), \ - 1, 1, array->size, 1, array->data_start); - return b; -} - -AI_API_DECLARE_END - -#endif /*__AI_DATATYPES_INTERNAL_H__*/ diff --git a/src/stm32cubeai/AI/Inc/ai_log.h b/src/stm32cubeai/AI/Inc/ai_log.h deleted file mode 100755 index c1bb39845..000000000 --- a/src/stm32cubeai/AI/Inc/ai_log.h +++ /dev/null @@ -1,140 +0,0 @@ -/** - * Copyright (c) 2017 rxi - * - * This library is free software; you can redistribute it and/or modify it - * under the terms of the MIT license. See `log.c` for details. - */ - -#ifndef AI_LOG_H_ -#define AI_LOG_H_ -#pragma once - -#include -#include -#include - -#ifdef __cplusplus -extern "C" { -#else -#include -#endif - -/*! - * @defgroup log Core logger class definition and implementation - * @brief Data structures and defines used to implementlogger module - * functionalities - */ - -#define LOG_VERSION "0.3.0" -#define LOG_CR "\r\n" - -/***** Compilation options: define/undef as required **************************/ -#define LOG_USE_COLOR -/* #define LOG_INFO_SOURCE_CODE */ - -#ifndef HAS_STM32 -#define LOG_USE_FILE -#define LOG_INFO_TIME -#define LOG_INFO_SOURCE_CODE_STRIP_FILE_PATHS '/' -#else -#define LOG_INFO_SOURCE_CODE_STRIP_FILE_PATHS '\\' -#endif - -/******************************************************************************/ -#define LOG_SUDO (0x0) -#define LOG_FATAL (0x1) -#define LOG_ERROR (0x2) -#define LOG_WARN (0x3) -#define LOG_INFO (0x4) -#define LOG_DEBUG (0x5) -#define LOG_TRACE (0x6) - - -/*! - * @typedef log_LockFn - * @ingroup ai_log - * @brief callback function for locking implementation (e.g. mutexes, etc.) - */ -typedef void (*log_LockFn)(const void *udata, const bool lock); - -/*! - * @typedef log_MsgFn - * @ingroup ai_log - * @brief callback for listening at logged channels - */ -typedef void (*log_MsgFn)( - const void *udata, const uint8_t level, - const char* msg, const uint32_t len); - -/*! - * @brief Get gloabal log context handle - * @ingroup ai_log - */ -void* ai_log_acquire(void); - -/*! - * @brief Set global log level - * @ingroup ai_log - */ -void ai_log_set_level(const uint8_t level); - -/*! - * @brief Set global log quiet mode (no messages are emitted) - * @ingroup ai_log - */ -void ai_log_set_quiet(const bool enable); - -/*! - * @brief Set callback for log messages locking - * @ingroup ai_log - */ -void ai_log_set_lock(log_LockFn fn, const void *udata); - -/*! - * @brief Push on log stack a new listener with given log level - * @ingroup ai_log - * @param[in] level the log level for this channel - * @param[out] the callback function to emit when a message is available - * @param[in] udata a pointer to the caller environment that is provided back - * when the callback is called - * @return 0 if OK, value>0 that indicates the current size of the stack - */ -uint8_t ai_log_channel_push(const uint8_t level, log_MsgFn fn, const void *udata); - -/*! - * @brief Pop from log stack a pushed listener - * @ingroup ai_log - * @param[in] the callback function registered during @ref log_channel_push - * @param[in] udata a pointer to the caller environment registered during @ref - * log_channel_push - * @return 0 if OK, value>0 that indicates the max size of the callback stack - */ -uint8_t ai_log_channel_pop(log_MsgFn fn, const void *udata); - -#ifdef LOG_USE_FILE -/*! - * @brief Enable file dumping of all logged messages to a file as well. - * @details NB: the quiet option does not apply to file logging. file log - * messages are recorded also when the log is in quiet mode. - * @ingroup ai_log - * @param[out] fp the file pointer of the file used to log the massages - */ -void ai_log_set_fp(FILE *fp); -#endif - -/*! - * @brief Main Routine: PLEASE invoke always by using defined macros - * @ingroup ai_log - * @param[in] level the log level of the input message - * @param[in] file the string containing the __FILE__ info about the source file - * generating the message to log - * @param[in] fmt the varargs format of the string to print - */ -void ai_log_log(const uint8_t level, const char *file, - const int line, const char *fmt, ...); - -#ifdef __cplusplus -} -#endif - -#endif /*AI_LOG_H_*/ diff --git a/src/stm32cubeai/AI/Inc/ai_math_helpers.h b/src/stm32cubeai/AI/Inc/ai_math_helpers.h deleted file mode 100755 index 09ba4844e..000000000 --- a/src/stm32cubeai/AI/Inc/ai_math_helpers.h +++ /dev/null @@ -1,301 +0,0 @@ -/** - ****************************************************************************** - * @file ai_math_helpers.h - * @author AST Embedded Analytics Research Platform - * @date 01-May-2017 - * @brief Math helpers routines header file. - ****************************************************************************** - * @attention - * - *

© Copyright (c) 2017 STMicroelectronics. - * All rights reserved.

- * - * This software component is licensed by ST under Ultimate Liberty license - * SLA0044, the "License"; You may not use this file except in compliance with - * the License. You may obtain a copy of the License at: - * www.st.com/SLA0044 - * - ****************************************************************************** - */ -#ifndef __AI_MATH_HELPERS_H_ -#define __AI_MATH_HELPERS_H_ -#include - -#include "ai_platform.h" -#include "ai_platform_interface.h" - -#define STM32_DOT_INLINE_OPTIM - -#define AI_FLOAT_TOLERANCE (6.19209290e-5F) /* Used for small calculation - noise issues */ -#define AI_FLOAT_EPSILON (1.19209290e-7F) -#define AI_I8_EPSILON (0.00787401F) /* 1/(2^7 - 1) */ -#define AI_I16_EPSILON (3.051851e-5F) /* 1/(2^15 - 1) */ - -#define AI_FLT_MAX (3.40282346638528859812e+38f) - -#define AI_MIN(x,y) ( ((x)<(y)) ? (x) : (y) ) -#define AI_MAX(x,y) ( ((x)>(y)) ? (x) : (y) ) -#define AI_SIGN(x) (((x)>0) ? 1 : -1) -#define AI_CLAMP(x, min, max) AI_MIN(AI_MAX(x,min), max) -#define AI_ABS(x) fabsf(x) -#define AI_ABS_DIFF(x, y) ( ((x)>(y)) ? ((x)-(y)) : ((y)-(x)) ) -#define AI_NEG(x) ( -1 * (x) ) -#define AI_RECIPROCAL(x) ( 1.0f / (x) ) -#define AI_CEIL(x) ceilf(x) -#define AI_FLOOR(x) floorf(x) -#define AI_FLOOR_DIV(x, y) AI_FLOOR((x)/(y)) /* floor division: x // y */ -#define AI_FLOOR_MOD(x, y) fmodf(x, y) -#define AI_ROUND(x) roundf(x) - -#if defined(STM32_DOT_INLINE_OPTIM) - -AI_DECLARE_STATIC -void __ai_math_dot_array( - ai_float* out, - const ai_float* data0, - const ai_float* data1, - ai_size data_size) -{ - ai_float sum = 0.0f; /* Temporary result storage */ - - /* Run the below code for Cortex-M4 and Cortex-M3 */ - - /* First part of the processing with loop unrolling. Compute 4 outputs at a time. - ** a second loop below computes the remaining 1 to 3 samples. */ - while (data_size >= 4u) - { - /* C = A[0]* B[0] + A[1]* B[1] + A[2]* B[2] + .....+ A[blockSize-1]* B[blockSize-1] */ - /* Calculate dot product and then store the result in a temporary buffer */ - sum += (*data0++) * (*data1++); - sum += (*data0++) * (*data1++); - sum += (*data0++) * (*data1++); - sum += (*data0++) * (*data1++); - - /* Decrement the loop counter */ - data_size -= 4u; - } - - while (data_size > 0u) - { - /* C = A[0]* B[0] + A[1]* B[1] + A[2]* B[2] + .....+ A[blockSize-1]* B[blockSize-1] */ - /* Calculate dot product and then store the result in a temporary buffer. */ - sum += (*data0++) * (*data1++); - - /* Decrement the loop counter */ - data_size--; - } - - /* Directly accumulate the result back in the destination buffer */ - *out += sum; -} - -#undef AI_MATH_DOT_ARRAY -#define AI_MATH_DOT_ARRAY(dst, src0, src1, size) \ - __ai_math_dot_array(dst, src0, src1, size) - - -#else - -#define AI_MATH_DOT_ARRAY(dst, src0, src1, size) \ - ai_math_dot_array(dst, src0, src1, size) - -#endif - -#define AI_MATH_ACOS(x) acosf(x) -#define AI_MATH_ACOSH(x) acoshf(x) -#define AI_MATH_ASIN(x) asinf(x) -#define AI_MATH_ASINH(x) asinhf(x) -#define AI_MATH_ATAN(x) atanf(x) -#define AI_MATH_ATANH(x) atanhf(x) -#define AI_MATH_COS(x) cosf(x) -#define AI_MATH_COSH(x) coshf(x) -#define AI_MATH_ERF(x) erff(x) -#define AI_MATH_EXP(x) expf(x) -#define AI_MATH_LOG(x) logf(x) -#define AI_MATH_POW(x, e) powf((x), (e)) -#define AI_MATH_RSQRT(x) (1.0f / AI_MATH_SQRT(x)) -#define AI_MATH_SIN(x) sinf(x) -#define AI_MATH_SINH(x) sinhf(x) -#define AI_MATH_SQRT(x) ai_math_sqrt(x) -#define AI_MATH_TAN(x) tanf(x) -#define AI_MATH_TANH(x) tanhf(x) - -#define AI_MATH_RELU_TEST(x, thr, min, max) \ - ( ((x)<(thr)) ? (min) : (max) ) - -#define AI_MATH_RELU_GENERIC(x, thr, alpha, max) \ - AI_MATH_RELU_TEST(x, max, AI_MATH_RELU_GENERIC_NO_MAX(x, thr, alpha), max) - -#define AI_MATH_RELU_GENERIC_NO_MAX(x, thr, alpha) \ - AI_MATH_RELU_TEST(x, thr, ((alpha)*((x)-(thr))), x) - -#define AI_MATH_RELU_THRESHOLDED(x, thr) \ - AI_MATH_RELU_TEST(x, thr, 0, (x)) - -#define AI_MATH_LEAKY_RELU(x, neg_slope, pos_slope) \ - AI_MATH_RELU_TEST(x, 0, (x)*(neg_slope), (x)*(pos_slope)) -// ( ((x)>0) ? (x)*(pos_slope) : (x)*(neg_slope) ) - -#define AI_MATH_PRELU(x, slope) \ - AI_MATH_RELU_TEST(x, 0, (x)*(slope), (x)) -// AI_MATH_LEAKY_RELU(x, slope, 1) - -#define AI_MATH_RELU(x) \ - AI_MATH_RELU_TEST(x, 0, 0, x) -// AI_MAX(x, 0) - -#define AI_MATH_ELU(x, alpha) \ - (AI_MAX(0.0f, (x)) + AI_MIN(0.0f, (alpha) * (AI_MATH_EXP(x)-1.0f))) - -#define AI_MATH_SELU(x, alpha, scale) \ - ((scale)*AI_MATH_ELU(x, alpha)) - -#define AI_MATH_SCALED_TANH(x, alpha, beta) \ - ((alpha)*AI_MATH_TANH((beta)*(x))) - -#define AI_MATH_SIGMOID(x) \ - (1.0f / (1.0f + AI_MATH_EXP(-(x)))) - -#define AI_MATH_HARD_SIGMOID(x, alpha, beta) \ - (AI_MAX(0.0f, AI_MIN(1.0f, (x) * (alpha) + (beta)))) - -#define AI_MATH_SOFT_PLUS(x) \ - AI_MATH_LOG(AI_MATH_EXP(x)+1.0f) - -#define AI_MATH_SOFT_SIGN(x) \ - ((x)/(AI_ABS(x)+1.0f)) - -AI_API_DECLARE_BEGIN - -/*! - * @defgroup math_helpers Math helpers - * @brief Common math functions - * - * Math functions are mapped to the underlying platform through those utility - * functions. On x86 and ARM v7 they are mapped to the float math functions in - * the C99 standard library; on MCUs they are mapped to the ARM DSP functions. - */ - -/*! - * @brief platform optimized dot product of float vectors - * - * Computes the dot product between vectors and adds the result to out. - * @ingroup math_helpers - * @param out scalar result of the dot product - * @param data0 the first float vector - * @param data1 the second float vector - * @param data_size the size of both vectors - */ -AI_INTERFACE_ENTRY -void ai_math_dot_array( - ai_float* out, - const ai_float* data0, - const ai_float* data1, - const ai_size data_size); - -/*! - * @brief platform optimized square root on a float value - * @ingroup math_helpers - * @param x input value - * @return square root of the value - */ -AI_INTERFACE_ENTRY -ai_float ai_math_sqrt(const ai_float x); - -/*! - * @brief platform optimized exponential on a float value - * @ingroup math_helpers - * @param x input value - * @return exponential of the value - */ -AI_INTERFACE_ENTRY -ai_float ai_math_exp(const ai_float x); - -/*! - * @brief platform optimized pow on a float value - * @ingroup math_helpers - * @param x input value - * @param e input value - * @return pow of the value ^ e - */ -AI_INTERFACE_ENTRY -ai_float ai_math_pow(const ai_float x, const ai_float e); - -/*! - * @brief platform optimized tangent on a float value - * @ingroup math_helpers - * @param x input value - * @return hyperbolic tangent of the value - */ -AI_INTERFACE_ENTRY -ai_float ai_math_tanh(const ai_float x); - -/*! - * @brief platform optimized relu on a float value - * @ingroup math_helpers - * @param x input value - * @return relu of the value ( x if x>0 else 0) - */ -AI_INTERFACE_ENTRY -ai_float ai_math_relu(const ai_float x); - -/*! - * @brief platform optimized parametric relu on a float value - * @ingroup math_helpers - * @param x input value - * @param slope input value - * @return parametric relu of the value - */ -AI_INTERFACE_ENTRY -ai_float ai_math_prelu(const ai_float x, const ai_float slope); - -/*! - * @brief platform optimized parametric sigmoid on a float value - * @ingroup math_helpers - * @param x input value - * @return sigmoid of the value - */ -AI_INTERFACE_ENTRY -ai_float ai_math_sigmoid(const ai_float x); - -/*! - * @brief platform optimized parametric hard sigmoid on a float value - * @ingroup math_helpers - * @param x input value - * @return hard sigmoid of the value - */ -AI_INTERFACE_ENTRY -ai_float ai_math_hard_sigmoid(const ai_float x); - -/*! - * @brief platform optimized parametric sign function on a float value - * @ingroup math_helpers - * @param x input value - * @return sign of the value - */ -AI_INTERFACE_ENTRY -ai_float ai_math_sign(const ai_float x); - -/*! - * @brief optimized parametric rectified linear unit on a float value - * @ingroup math_helpers - * @param x input value - * @param slope parameter value - * @return x if x is positive and x*slope otherwise - */ -AI_INTERFACE_ENTRY -ai_float ai_fast_prelu(const ai_float x, const ai_float slope); - -AI_INTERFACE_ENTRY ai_float ai_div(const ai_float a, const ai_float b); -AI_INTERFACE_ENTRY ai_float ai_floor_div(const ai_float a, const ai_float b); -AI_INTERFACE_ENTRY ai_float ai_floor_mod(const ai_float a, const ai_float b); -AI_INTERFACE_ENTRY ai_float ai_max(const ai_float a, const ai_float b); -AI_INTERFACE_ENTRY ai_float ai_min(const ai_float a, const ai_float b); -AI_INTERFACE_ENTRY ai_float ai_mul(const ai_float a, const ai_float b); -AI_INTERFACE_ENTRY ai_float ai_sub(const ai_float a, const ai_float b); -AI_INTERFACE_ENTRY ai_float ai_sum(const ai_float a, const ai_float b); - -AI_API_DECLARE_END - -#endif /* __MATH_HELPERS_H_ */ diff --git a/src/stm32cubeai/AI/Inc/ai_network_inspector.h b/src/stm32cubeai/AI/Inc/ai_network_inspector.h deleted file mode 100755 index 2956fc428..000000000 --- a/src/stm32cubeai/AI/Inc/ai_network_inspector.h +++ /dev/null @@ -1,176 +0,0 @@ -/** - ****************************************************************************** - * @file ai_network_inspector.h - * @author AST Embedded Analytics Research Platform - * @date 6-Aug-2018 - * @brief header file of the network inspector wrapper plugin - ****************************************************************************** - * @attention - * - *

© Copyright (c) 2018 STMicroelectronics. - * All rights reserved.

- * - * This software component is licensed by ST under Ultimate Liberty license - * SLA0044, the "License"; You may not use this file except in compliance with - * the License. You may obtain a copy of the License at: - * www.st.com/SLA0044 - * - ****************************************************************************** - */ - -#ifndef __AI_NETWORK_INSPECTOR_H_ -#define __AI_NETWORK_INSPECTOR_H_ -#pragma once - -#include "ai_platform.h" -#include "ai_platform_interface.h" -#include "core_net_inspect_interface.h" - -#define AI_INSPECTOR_API_MAJOR 1 -#define AI_INSPECTOR_API_MINOR 1 -#define AI_INSPECTOR_API_MICRO 0 - -/*! - * @defgroup ai_network_inspector AI Network Inspector Module Tool - * @brief header with datatypes and APIs for inspector module - */ - -#define AI_INSPECTOR_NETWORK_BIND_FAILED (0x0) - - -AI_API_DECLARE_BEGIN - -/*! - * @typedef ai_inspector_entry_id - * @ingroup ai_network_inspector - * @brief network inspector bind network index id number - * (actually the inspector could bind up to 65534 networks) - */ -typedef ai_u16 ai_inspector_entry_id; - -/*! - * @typedef ai_inspector_net_info - * @ingroup ai_network_inspector - * @brief wrapper struct for @ref ai_network_report - */ -typedef ai_network_report ai_inspector_net_info; - -/*! - * @typedef ai_inspector_config - * @ingroup ai_network_inspector - * @brief wrapper struct for @ref ai_inspect_config - */ -typedef ai_inspect_config ai_inspector_config; - -/*! - * @typedef ai_inspector_node_info - * @ingroup ai_network_inspector - * @brief wrapper struct for @ref ai_inspect_node_info - */ -typedef ai_inspect_node_info ai_inspector_node_info; - -/*! - * @typedef ai_inspector_net_report - * @ingroup ai_network_inspector - * @brief wrapper struct for @ref ai_inspect_net_report - */ -typedef ai_inspect_net_report ai_inspector_net_report; - -/*! - * @struct ai_inspector_net_entry - * @ingroup ai_network_inspector - * @brief struct with info related to the bound network. It has the network - * handle, the network params, and the error (see @ref ai_error definition) - */ -typedef struct ai_inspector_net_entry_ { - ai_handle handle; /*!< bound network context handle */ - ai_network_params params; /*!< bound network context params */ - ai_error error; /*!< bound network context error */ -} ai_inspector_net_entry; - -/*! - * @brief Return default context config. - * @ingroup ai_network_inspector - * @param[out] inspector config datastructure - * @return the default inspector configuration - */ -AI_API_ENTRY -ai_inspector_config ai_inspector_default_config(void); - -/*! - * @brief Create a network inspector plugin module. - * @ingroup ai_network_inspector - * @param[out] handle a pointer to an opaque handle that points to the inspector - * context created - * @param[in] cfg a pointer to the inspector config. if NULL a default config is - * used by the inspector instance - * @return true if initialization was fine, false otherwise - */ -AI_API_ENTRY -ai_bool ai_inspector_create( - ai_handle* handle, const ai_inspector_config* cfg); - -/*! - * @brief Destroy a network inspector plugin module. - * @ingroup ai_network_inspector - * @param[in/out] handle an opaque handle to the inspector context to destroy - * context - * @return true if destroy was fine, false otherwise - */ -AI_API_ENTRY -ai_bool ai_inspector_destroy(ai_handle handle); - -/*! - * @brief Bind a network instance with the inspector plugin - * @ingroup ai_network_inspector - * @param[in/out] handle an opaque handle to the inspector context - * @param[in] entry a pointer to the info about the network to be bound - * @return a network id > 0 that is an index used to refer to the bound - * network instance. if the returned index is 0 an error occurred during binding - */ -AI_API_ENTRY -ai_inspector_entry_id ai_inspector_bind_network( - ai_handle handle, const ai_inspector_net_entry* entry); - -/*! - * @brief Unbind a network instance from the inspector plugin - * @ingroup ai_network_inspector - * @param[in/out] handle an opaque handle to the inspector context - * @param[in] net_id: a network id provided by @ref ai_inspector_bind_network API - * @return true if the unbind was successful, false otherwise - */ -AI_API_ENTRY -ai_bool ai_inspector_unbind_network( - ai_handle handle, const ai_inspector_entry_id net_id); - -/*! - * @brief Get inspection report on a bind network - * @ingroup ai_network_inspector - * @param[in/out] handle an opaque handle to the inspector context - * @param[in] net_id: a network id provided by @ref ai_inspector_bind_network API - * @param[out] report a pointer to the required report @ref ai_inspector_net_report - * data struct - * @return true if the query was successful, false otherwise - */ -AI_API_ENTRY -ai_bool ai_inspector_get_report( - ai_handle handle, const ai_inspector_entry_id net_id, - ai_inspector_net_report* report); - -/*! - * @brief Run a network instance bind to the inspector - * @ingroup ai_network_inspector - * @param[in/out] handle an opaque handle to the inspector context - * @param[in] net_id: a network id provided by @ref ai_inspector_bind_network API - * @param[in] input a pointer to the input data buffer - * @param[out] outbut a pointer to the output data buffer - * @return the number of batches processed. a value <=0 indicates an error - */ -AI_API_ENTRY -ai_i32 ai_inspector_run( - ai_handle handle, const ai_inspector_entry_id net_id, - const ai_buffer* input, ai_buffer* output); - -AI_API_DECLARE_END - -#endif /* __AI_NETWORK_INSPECTOR_H_ */ diff --git a/src/stm32cubeai/AI/Inc/ai_platform.h b/src/stm32cubeai/AI/Inc/ai_platform.h deleted file mode 100755 index e3c9ff462..000000000 --- a/src/stm32cubeai/AI/Inc/ai_platform.h +++ /dev/null @@ -1,508 +0,0 @@ -/** - ****************************************************************************** - * @file ai_platform.h - * @author AST Embedded Analytics Research Platform - * @date 01-May-2017 - * @brief Definitions of AI platform public APIs types - ****************************************************************************** - * @attention - * - *

© Copyright (c) 2017 STMicroelectronics. - * All rights reserved.

- * - * This software component is licensed by ST under Ultimate Liberty license - * SLA0044, the "License"; You may not use this file except in compliance with - * the License. You may obtain a copy of the License at: - * www.st.com/SLA0044 - * - ****************************************************************************** - */ - -#ifndef __AI_PLATFORM_H__ -#define __AI_PLATFORM_H__ -#pragma once - -#include - -#define AI_PLATFORM_API_MAJOR 1 -#define AI_PLATFORM_API_MINOR 1 -#define AI_PLATFORM_API_MICRO 0 - -/******************************************************************************/ -#ifdef __cplusplus -#define AI_API_DECLARE_BEGIN extern "C" { -#define AI_API_DECLARE_END } -#else -#include -#define AI_API_DECLARE_BEGIN /* AI_API_DECLARE_BEGIN */ -#define AI_API_DECLARE_END /* AI_API_DECLARE_END */ -#endif - -/******************************************************************************/ -#define AI_CONCAT_ARG(a, b) a ## b -#define AI_CONCAT(a, b) AI_CONCAT_ARG(a, b) - -/******************************************************************************/ -#if defined(_MSC_VER) - #define AI_API_ENTRY __declspec(dllexport) - #define AI_ALIGNED(x) /* AI_ALIGNED(x) */ -#elif defined(__ICCARM__) || defined (__IAR_SYSTEMS_ICC__) - #define AI_API_ENTRY /* AI_API_ENTRY */ - #define AI_ALIGNED(x) AI_CONCAT(AI_ALIGNED_,x) - #define AI_ALIGNED_1 _Pragma("data_alignment = 1") - #define AI_ALIGNED_2 _Pragma("data_alignment = 2") - #define AI_ALIGNED_4 _Pragma("data_alignment = 4") - #define AI_ALIGNED_8 _Pragma("data_alignment = 8") -#elif defined(__CC_ARM) - #define AI_API_ENTRY __attribute__((visibility("default"))) - #define AI_ALIGNED(x) __attribute__((aligned (x))) - /* Keil disallows anonymous union initialization by default */ - #pragma anon_unions -#elif defined(__GNUC__) - #define AI_API_ENTRY __attribute__((visibility("default"))) - #define AI_ALIGNED(x) __attribute__((aligned(x))) -#else - /* Dynamic libraries are not supported by the compiler */ - #define AI_API_ENTRY /* AI_API_ENTRY */ - #define AI_ALIGNED(x) /* AI_ALIGNED(x) */ -#endif - -#define AI_HANDLE_PTR(ptr_) ((ai_handle)(ptr_)) -#define AI_HANDLE_NULL AI_HANDLE_PTR(0) - -#define AI_HANDLE_FUNC_PTR(func) ((ai_handle_func)(func)) - -#define AI_UNUSED(x) (void)(x); - -#define AI_DEPRECATED /* AI_DEPRECATED */ - -#define AI_LEGACY /* AI_LEGACY */ - -#ifndef __GNUC__ - #define AI_STRUCT_INIT {0} -#else - #define AI_STRUCT_INIT {} -#endif - -#define AI_ERROR_FMT AIU32_FMT - -#define AI_IS_UNSIGNED(type) \ - ((((type)0) - 1) > 0) - -#define AI_CUSTOM_SIZE(type) \ - (ai_custom_type_signature)((AI_IS_UNSIGNED(type)) \ - ? (0x80|(sizeof(type)&0x7f)) : (sizeof(type)&0x7f)) - -#define AI_NETWORK_PARAMS_INIT(params_, activations_) { \ - .params = params_, \ - .activations = activations_ } - -/*! ai_intq_info struct handlers **********************************************/ -#define AI_INTQ_INFO_LIST_FLAGS(list_) \ - ( (list_) ? (list_)->flags : 0 ) - -#define AI_INTQ_INFO_LIST_SCALE(list_, type_, pos_) \ - ( ((list_) && (list_)->info && ((pos_)<(list_)->size)) \ - ? ((type_*)((list_)->info->scale))[(pos_)] : 0 ) - -#define AI_INTQ_INFO_LIST_ZEROPOINT(list_, type_, pos_) \ - ( ((list_) && (list_)->info && ((pos_)<(list_)->size)) \ - ? ((type_*)((list_)->info->zeropoint))[(pos_)] : 0 ) - -/*! ai_buffer format handlers *************************************************/ - -/*! - * @enum buffer format definition - * @ingroup ai_platform - * - * 32 bit signed format list. - */ -typedef int32_t ai_buffer_format; - -/*! ai_buffer_meta flags ******************************************************/ -#define AI_BUFFER_META_HAS_INTQ_INFO (0x1U << 0) -#define AI_BUFFER_META_FLAG_SCALE_FLOAT (0x1U << 0) -#define AI_BUFFER_META_FLAG_ZEROPOINT_U8 (0x1U << 1) -#define AI_BUFFER_META_FLAG_ZEROPOINT_S8 (0x1U << 2) - -/*! ai_buffer format variable flags *******************************************/ -#define AI_BUFFER_FMT_TYPE_NONE (0x0) -#define AI_BUFFER_FMT_TYPE_FLOAT (0x1) -#define AI_BUFFER_FMT_TYPE_Q (0x2) - -#define AI_BUFFER_FMT_FLAG_CONST (0x1U<<30) -#define AI_BUFFER_FMT_FLAG_STATIC (0x1U<<29) -#define AI_BUFFER_FMT_FLAG_IS_IO (0x1U<<27) - -#define AI_BUFFER_FMT_PACK(value_, mask_, bits_) \ - ( ((value_) & (mask_)) << (bits_) ) - -#define AI_BUFFER_FMT_UNPACK(fmt_, mask_, bits_) \ - ( (AI_BUFFER_FMT_OBJ(fmt_) >> (bits_)) & (mask_) ) - -#define AI_BUFFER_FMT_OBJ(fmt_) \ - ((ai_buffer_format)(fmt_)) - -#define AI_BUFFER_FMT_GET_FLOAT(fmt_) \ - AI_BUFFER_FMT_UNPACK(fmt_, 0x1, 24) - -#define AI_BUFFER_FMT_GET_SIGN(fmt_) \ - AI_BUFFER_FMT_UNPACK(fmt_, 0x1, 23) - -#define AI_BUFFER_FMT_GET_TYPE(fmt_) \ - AI_BUFFER_FMT_UNPACK(fmt_, 0xF, 17) - -#define AI_BUFFER_FMT_GET_BITS(fmt_) \ - AI_BUFFER_FMT_UNPACK(fmt_, 0x7F, 7) - -#define AI_BUFFER_FMT_SET_BITS(bits_) \ - AI_BUFFER_FMT_PACK((bits_), 0x7F, 7) - -#define AI_BUFFER_FMT_GET_FBITS(fmt_) \ - ( (ai_i8)AI_BUFFER_FMT_UNPACK(fmt_, 0x7F, 0) - 64 ) - -#define AI_BUFFER_FMT_SET_FBITS(fbits_) \ - AI_BUFFER_FMT_PACK((fbits_)+64, 0x7F, 0) - -#define AI_BUFFER_FMT_SET(type_id_, sign_bit_, float_bit_, bits_, fbits_) \ - AI_BUFFER_FMT_OBJ( \ - AI_BUFFER_FMT_PACK(float_bit_, 0x1, 24) | \ - AI_BUFFER_FMT_PACK(sign_bit_, 0x1, 23) | \ - AI_BUFFER_FMT_PACK(0, 0x3, 21) | \ - AI_BUFFER_FMT_PACK(type_id_, 0xF, 17) | \ - AI_BUFFER_FMT_PACK(0, 0x7, 14) | \ - AI_BUFFER_FMT_SET_BITS(bits_) | \ - AI_BUFFER_FMT_SET_FBITS(fbits_) \ - ) - -#define AI_BUFFER_FMT_SAME(fmt1_, fmt2_) \ - ( AI_BUFFER_FMT_GET(fmt1_) == AI_BUFFER_FMT_GET(fmt2_) ) - -#define AI_BUFFER_FMT_GET(fmt_) \ - (AI_BUFFER_FMT_OBJ(fmt_) & 0x01FFFFFF) - -#define AI_BUFFER_FORMAT(buf_) \ - AI_BUFFER_FMT_GET((buf_)->format) -#define AI_BUFFER_WIDTH(buf_) \ - ((buf_)->width) -#define AI_BUFFER_HEIGHT(buf_) \ - ((buf_)->height) -#define AI_BUFFER_CHANNELS(buf_) \ - ((buf_)->channels) -#define AI_BUFFER_N_BATCHES(buf_) \ - ((buf_)->n_batches) -#define AI_BUFFER_DATA(buf_, type_) \ - ((type_*)((buf_)->data)) - -#define AI_BUFFER_META_INFO(buf_) \ - ((buf_)->meta_info) - -#define AI_BUFFER_META_INFO_INTQ(meta_) \ - ((meta_) && ((meta_)->flags & AI_BUFFER_META_HAS_INTQ_INFO)) \ - ? ((meta_)->intq_info) : NULL - -#define AI_BUFFER_META_INFO_INTQ_GET_SCALE(meta_, pos_) \ - ( (AI_BUFFER_META_INFO_INTQ(meta_)) \ - ? AI_INTQ_INFO_LIST_SCALE(AI_BUFFER_META_INFO_INTQ(meta_), ai_float, pos_) \ - : 0 ) - -#define AI_BUFFER_META_INFO_INTQ_GET_ZEROPOINT(meta_, pos_) \ - ( (AI_BUFFER_META_INFO_INTQ(meta_)) \ - ? ((AI_INTQ_INFO_LIST_FLAGS(AI_BUFFER_META_INFO_INTQ(meta_))&AI_BUFFER_META_FLAG_ZEROPOINT_U8) \ - ? AI_INTQ_INFO_LIST_ZEROPOINT(AI_BUFFER_META_INFO_INTQ(meta_), ai_u8, pos_) \ - : AI_INTQ_INFO_LIST_ZEROPOINT(AI_BUFFER_META_INFO_INTQ(meta_), ai_i8, pos_) ) \ - : 0 ) - -#define AI_BUFFER_META_INFO_INIT(flags_, intq_info_) { \ - .flags = (flags_), \ - .intq_info = AI_PACK(intq_info_) \ -} - -#define AI_BUFFER_SIZE(buf_) \ - (((buf_)->width) * ((buf_)->height) * ((buf_)->channels)) - -#define AI_BUFFER_BYTE_SIZE(count_, fmt_) \ - ( (((count_) * AI_BUFFER_FMT_GET_BITS(fmt_))+4) >> 3 ) - - -#define AI_BUFFER_OBJ_INIT(format_, h_, w_, ch_, n_batches_, data_) \ -{ .format = (ai_buffer_format)(format_), \ - .n_batches = (n_batches_), \ - .height = (h_), \ - .width = (w_), \ - .channels = (ch_), \ - .data = (ai_handle)(data_), \ - .meta_info = NULL \ -} - -#define AI_BUFFER_OBJ_INIT_STATIC(type_, format_, h_, w_, ch_, n_batches_, ...) \ -{ .format = (ai_buffer_format)(format_), \ - .n_batches = (n_batches_), \ - .height = (h_), \ - .width = (w_), \ - .channels = (ch_), \ - .data = (ai_handle)((type_[(h_)*(w_)*(ch_)*(n_batches_)]){__VA_ARGS__}), \ - .meta_info = NULL \ -} - -/*! - * @enum buffer formats enum list - * @ingroup ai_platform - * - * List of supported ai_buffer format types. - */ -enum { - AI_BUFFER_FORMAT_NONE = AI_BUFFER_FMT_SET(AI_BUFFER_FMT_TYPE_NONE, 0, 0, 0, 0), - AI_BUFFER_FORMAT_FLOAT = AI_BUFFER_FMT_SET(AI_BUFFER_FMT_TYPE_FLOAT, 1, 1, 32, 0), - - AI_BUFFER_FORMAT_U8 = AI_BUFFER_FMT_SET(AI_BUFFER_FMT_TYPE_Q, 0, 0, 8, 0), - AI_BUFFER_FORMAT_U16 = AI_BUFFER_FMT_SET(AI_BUFFER_FMT_TYPE_Q, 0, 0, 16, 0), - AI_BUFFER_FORMAT_S8 = AI_BUFFER_FMT_SET(AI_BUFFER_FMT_TYPE_Q, 1, 0, 8, 0), - AI_BUFFER_FORMAT_S16 = AI_BUFFER_FMT_SET(AI_BUFFER_FMT_TYPE_Q, 1, 0, 16, 0), - - AI_BUFFER_FORMAT_Q = AI_BUFFER_FMT_SET(AI_BUFFER_FMT_TYPE_Q, 1, 0, 0, 0), - AI_BUFFER_FORMAT_Q7 = AI_BUFFER_FMT_SET(AI_BUFFER_FMT_TYPE_Q, 1, 0, 8, 7), - AI_BUFFER_FORMAT_Q15 = AI_BUFFER_FMT_SET(AI_BUFFER_FMT_TYPE_Q, 1, 0, 16, 15), - - AI_BUFFER_FORMAT_UQ = AI_BUFFER_FMT_SET(AI_BUFFER_FMT_TYPE_Q, 0, 0, 0, 0), - AI_BUFFER_FORMAT_UQ7 = AI_BUFFER_FMT_SET(AI_BUFFER_FMT_TYPE_Q, 0, 0, 8, 7), - AI_BUFFER_FORMAT_UQ15 = AI_BUFFER_FMT_SET(AI_BUFFER_FMT_TYPE_Q, 0, 0, 16, 15), -}; - -/******************************************************************************/ -#define AI_ERROR_INIT(type_, code_) { \ - .type = AI_ERROR_##type_, \ - .code = AI_ERROR_CODE_##code_ } - -/* printf formats */ -#ifdef REISC - #define SSIZET_FMT "%lu" - #define AII32_FMT "%ld" - #define AIU32_FMT "%lu" -#else /* REISC */ - #define SSIZET_FMT "%u" - #define AII32_FMT "%d" - #define AIU32_FMT "%u" -#endif /* REISC */ - -typedef uint8_t ai_custom_type_signature; - -typedef void* ai_handle; - -typedef void (*ai_handle_func)(void*); - -typedef float ai_float; -typedef double ai_double; - -typedef bool ai_bool; - -typedef uint32_t ai_size; - -typedef uintptr_t ai_uptr; - -typedef unsigned int ai_uint; -typedef uint8_t ai_u8; -typedef uint16_t ai_u16; -typedef uint32_t ai_u32; -typedef uint64_t ai_u64; - -typedef int ai_int; -typedef int8_t ai_i8; -typedef int16_t ai_i16; -typedef int32_t ai_i32; -typedef int64_t ai_i64; - -typedef uint32_t ai_signature; - -/******************************************************************************/ -/*! - * @struct ai_error - * @ingroup ai_platform - * @brief Structure encoding details about the last error. - */ -typedef struct ai_error_ { - ai_u32 type : 8; /*!< Error type represented by @ref ai_error_type */ - ai_u32 code : 24; /*!< Error code represented by @ref ai_error_code */ -} ai_error; - -/******************************************************************************/ -/*! - * @struct ai_intq_info - * @ingroup ai_platform - * @brief an element of the ai_intq_info_list entry. It reports an array for the - * scale and zeropoint values for each buffer. Optional flags are also present - */ -typedef struct ai_intq_info_ { - ai_float* scale; - ai_handle zeropoint; -} ai_intq_info; - -/*! - * @struct ai_intq_info_list - * @ingroup ai_platform - * @brief list reporting meta info for quantized networks integer support - * when size > 1 it means a per channel out quantization - */ -typedef struct ai_intq_info_list_ { - ai_u16 flags; /*!< optional flags to store intq info attributes */ - ai_u16 size; /*!< number of elements in the the intq_info list */ - ai_intq_info* info; /*!< pointer to an array of metainfo associated to the intq_info list */ -} ai_intq_info_list; - -/******************************************************************************/ -/*! - * @struct ai_buffer_meta_info - * @ingroup ai_platform - * @brief Optional meta attributes associated with the I/O buffer. - * This datastruct is used also for network querying, where the data field may - * may be NULL. - */ -typedef struct ai_buffer_meta_info_ { - ai_u32 flags; /*!< meta info flags */ - ai_intq_info_list* intq_info; /*!< meta info related to integer format */ -} ai_buffer_meta_info; - -/*! - * @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_meta_info* meta_info; /*!< pointer to buffer metadata info */ -} ai_buffer; - -/* enums section */ - -/*! - * @enum ai_error_type - * @ingroup ai_platform - * - * Generic enum to list network error types. - */ -typedef enum { - AI_ERROR_NONE = 0x00, /*!< No error */ - AI_ERROR_TOOL_PLATFORM_MISMATCH = 0x01, - AI_ERROR_TYPES_MISMATCH = 0x02, - AI_ERROR_INVALID_HANDLE = 0x10, - AI_ERROR_INVALID_STATE = 0x11, - AI_ERROR_INVALID_INPUT = 0x12, - AI_ERROR_INVALID_OUTPUT = 0x13, - AI_ERROR_INVALID_PARAM = 0x14, - AI_ERROR_INVALID_SIGNATURE = 0x15, - AI_ERROR_INIT_FAILED = 0x30, - AI_ERROR_ALLOCATION_FAILED = 0x31, - AI_ERROR_DEALLOCATION_FAILED = 0x32, -} ai_error_type; - -/*! - * @enum ai_error_code - * @ingroup ai_platform - * - * Generic enum to list network error codes. - */ -typedef enum { - AI_ERROR_CODE_NONE = 0x0000, /*!< No error */ - AI_ERROR_CODE_NETWORK = 0x0010, - AI_ERROR_CODE_NETWORK_PARAMS = 0x0011, - AI_ERROR_CODE_NETWORK_WEIGHTS = 0x0012, - AI_ERROR_CODE_NETWORK_ACTIVATIONS = 0x0013, - AI_ERROR_CODE_LAYER = 0x0014, - AI_ERROR_CODE_TENSOR = 0x0015, - AI_ERROR_CODE_ARRAY = 0x0016, - AI_ERROR_CODE_INVALID_PTR = 0x0017, - AI_ERROR_CODE_INVALID_SIZE = 0x0018, - AI_ERROR_CODE_INVALID_FORMAT = 0x0019, - AI_ERROR_CODE_OUT_OF_RANGE = 0x0020, - AI_ERROR_CODE_INVALID_BATCH = 0x0021, - AI_ERROR_CODE_MISSED_INIT = 0x0030, -} ai_error_code; - -/*! - * @struct ai_platform_version - * @ingroup ai_platform - * @brief Datastruct storing platform version info - */ -typedef struct ai_platform_version_ { - ai_u8 major; - ai_u8 minor; - ai_u8 micro; - ai_u8 reserved; -} ai_platform_version; - - -/*! - * @struct ai_network_params - * @ingroup ai_platform - * - * Datastructure to pass parameters to the network initialization. - */ -typedef struct ai_network_params_ { - ai_buffer params; /*! info about params buffer(required!) */ - ai_buffer activations; /*! info about activations buffer (required!) */ -} ai_network_params; - -/*! - * @struct ai_network_report - * @ingroup ai_platform - * - * Datastructure to query a network report with some relevant network detail. - */ -typedef struct ai_network_report_ { - const char* model_name; - const char* model_signature; - const char* model_datetime; - - const char* compile_datetime; - - const char* runtime_revision; - ai_platform_version runtime_version; - - const char* tool_revision; - ai_platform_version tool_version; - ai_platform_version tool_api_version; - - ai_platform_version api_version; - ai_platform_version interface_api_version; - - ai_u32 n_macc; - - ai_u16 n_inputs; - ai_u16 n_outputs; - ai_buffer* inputs; - ai_buffer* outputs; - - ai_buffer activations; - ai_buffer params; - - ai_u32 n_nodes; - - ai_signature signature; -} ai_network_report; - -/*! - * @enum ai_upsample_mode - * @ingroup ai_platform - * @brief allowed mode in upsample layer - */ -typedef enum { - AI_UPSAMPLE_ZEROS = 0x0, - AI_UPSAMPLE_NEAREST, - AI_UPSAMPLE_BILINEAR, - AI_UPSAMPLE_TRILINEAR -} ai_upsample_mode; - -typedef enum { - AI_PAD_CONSTANT = 0x0, - AI_PAD_REFLECT, - AI_PAD_EDGE, -} ai_pad_mode; - -#endif /*__AI_PLATFORM_H__*/ diff --git a/src/stm32cubeai/AI/Inc/ai_platform_interface.h b/src/stm32cubeai/AI/Inc/ai_platform_interface.h deleted file mode 100755 index 394b78745..000000000 --- a/src/stm32cubeai/AI/Inc/ai_platform_interface.h +++ /dev/null @@ -1,786 +0,0 @@ -/** - ****************************************************************************** - * @file ai_platform_interface.h - * @author AST Embedded Analytics Research Platform - * @date 02-Aug-2018 - * @brief Definitions of AI platform interface APIs types - ****************************************************************************** - * @attention - * - *

© Copyright (c) 2018 STMicroelectronics. - * All rights reserved.

- * - * This software component is licensed by ST under Ultimate Liberty license - * SLA0044, the "License"; You may not use this file except in compliance with - * the License. You may obtain a copy of the License at: - * www.st.com/SLA0044 - * - ****************************************************************************** - */ - -#ifndef __AI_PLATFORM_INTERFACE_H__ -#define __AI_PLATFORM_INTERFACE_H__ -#pragma once - -#include "ai_platform.h" - -#include "datatypes_network.h" -#include "ai_datatypes_format.h" - -/*! - * @defgroup datatypes_interface Interface Datatypes - * @brief Data structures and defines used to implement neural networks - */ - -#define AI_PLATFORM_INTERFACE_API_MAJOR 1 -#define AI_PLATFORM_INTERFACE_API_MINOR 3 -#define AI_PLATFORM_INTERFACE_API_MICRO 0 - -/******************************************************************************/ -#define AI_ERROR_TRAP(net_, type_, code_) \ - ai_platform_network_set_error((net_), AI_CONCAT(AI_ERROR_,type_), \ - AI_CONCAT(AI_ERROR_CODE_,code_)) - -/*! AI_PTR HANDLERS SECTION ************************************/ -#define AI_PTR(ptr_) ((ai_ptr)(ptr_)) -#define AI_PTR_CONST(ptr_) ((ai_ptr_const)(ptr_)) - -/*! STATIC ARRAYS ALLOCATOR SECTION ************************************/ -#define AI_PACK_STORAGE_ARRAY(type_, dim_, ...) \ - (type_[dim_]) { AI_PACK(__VA_ARGS__) } - -/*! AI_STORAGE_KLASS SECTION ************************************/ -#define AI_STORAGE_KLASS_PACK(type_, dim_, ...) \ - AI_PACK_STORAGE_ARRAY(type_, dim_, __VA_ARGS__) - -#define AI_STORAGE_KLASS_INIT(type_, size_, data_) \ -{ \ - .type = (type_), \ - .size = (size_), \ - .data = (ai_handle)(data_), \ -} - -/*! - * @enum ai_storage_klass_type - * @ingroup ai_platform_interface - * @brief @ref ai_storage_class types enum - */ -typedef enum { - AI_STORAGE_KLASS_SHAPE = 0x0, - AI_STORAGE_KLASS_STRIDE, - AI_STORAGE_KLASS_FLOAT, - AI_STORAGE_KLASS_U8, - AI_STORAGE_KLASS_I8, - AI_STORAGE_KLASS_U16, - AI_STORAGE_KLASS_I16, - AI_STORAGE_KLASS_U32, - AI_STORAGE_KLASS_I32, - AI_STORAGE_KLASS_U64, - AI_STORAGE_KLASS_I64, -} ai_storage_klass_type; - -/*! - * @struct ai_storage_klass - * @ingroup ai_platform_interface - * @brief Generic "Template" klass for generic storage arrays containers - * from this klass several typed containers are derived (see e.g. @ref ai_shape) - */ -AI_PACKED_STRUCT_START -typedef AI_ALIGNED_TYPE(struct, 4) AI_PACKED ai_storage_klass_s { - ai_u32 type : 8; - ai_u32 size : 24; - ai_handle data; -} ai_storage_klass; -AI_PACKED_STRUCT_END - -/*! AI_SHAPES SECTION ************************************/ -#define AI_SHAPE_2D_INIT(w_, h_) \ - { .data = { (w_), (h_) } } - -#define AI_SHAPE_INIT(dim_, ...) \ - AI_STORAGE_KLASS_INIT( \ - AI_STORAGE_KLASS_SHAPE, \ - dim_, \ - AI_STORAGE_KLASS_PACK(ai_shape_dimension, dim_, ## __VA_ARGS__)) - -#define AI_SHAPE_INIT_FROM_BUFFER(dim_, buffer_) \ - AI_STORAGE_KLASS_INIT( \ - AI_STORAGE_KLASS_SHAPE, \ - dim_, \ - buffer_) - -/*! - * @enum ai_shape_type - * @ingroup ai_platform_interface - * @brief Codes for the 4D tensor dimensions - */ -typedef enum { - AI_SHAPE_MAX_DIMENSION = 0x4, - AI_SHAPE_HEIGHT = 0x3, - AI_SHAPE_WIDTH = 0x2, - AI_SHAPE_CHANNEL = 0x1, - AI_SHAPE_IN_CHANNEL = 0x0, -// AI_SHAPE_BATCH_CHANNEL = 0x4, -} ai_shape_type; - -/*! - * @struct ai_shape - * @ingroup ai_platform_interface - * @brief Dimensions for generic 4D tensors - */ -#if 1 - -#if 0 -AI_PACKED_STRUCT_START -typedef AI_ALIGNED_TYPE(struct, 4) AI_PACKED ai_shape_s { - ai_u32 type : 8; - ai_u32 size : 24; - ai_shape_dimension data[AI_SHAPE_MAX_DIMENSION]; /*!< 4D tensor shape */ -} ai_shape; -AI_PACKED_STRUCT_END -#else -typedef ai_storage_klass ai_shape; -#endif - -#else -AI_PACKED_STRUCT_START -typedef AI_ALIGNED_TYPE(struct, 4) AI_PACKED ai_shape_s { - ai_shape_dimension* dimension; /*!< ND tensor shape */ -} ai_shape; -AI_PACKED_STRUCT_END -#endif - -/*! AI_STRIDES HANDLERS SECTION ************************************/ -#define AI_STRIDE_INIT(dim_, ...) \ - AI_STORAGE_KLASS_INIT( \ - AI_STORAGE_KLASS_STRIDE, \ - dim_, \ - AI_STORAGE_KLASS_PACK(ai_stride_dimension, dim_, ## __VA_ARGS__)) - - -#define AI_STRIDE_INIT_FROM_BUFFER(dim_, buffer_) \ - AI_STORAGE_KLASS_INIT( \ - AI_STORAGE_KLASS_STRIDE, \ - dim_, \ - buffer_) - -/*! - * @struct ai_stride - * @ingroup ai_platform_interface - * @brief Stride dimensions for generic 4D tensors (in number of elements) - */ -typedef ai_storage_klass ai_stride; - -/*! BASIC_TYPES HANDLERS SECTION ************************************/ -#define AI_SIZE(value_) \ - ((ai_size)(value_)) - -/*! AI_KLASS_OBJ HANDLERS SECTION ************************************/ -#define AI_KLASS_OBJ(obj_) \ - ((ai_klass_obj)(obj_)) - -/*! GENERIC HANDLERS SECTION ************************************/ -#define AI_OBJ_DATA(obj_, type_) \ - ((type_)(obj_)->data) - -/*! AI_BUFFER HANDLERS SECTION ************************************/ -#define AI_BUFFER_OBJ(ptr) \ - ((ai_buffer*)(ptr)) - -/*! AI_ARRAY HANDLERS SECTION ************************************/ -#define AI_ARRAY_OBJ(ptr) \ - ((ai_array*)(ptr)) - -#define AI_ARRAY_OBJ_FMT(array_) \ - ((ai_array_format)(AI_ARRAY_OBJ(array_)->format)) - -#define AI_ARRAY_OBJ_SIZE(array_) \ - (AI_ARRAY_OBJ(array_)->size) - -#define AI_ARRAY_OBJ_BYTE_SIZE(array_) \ - AI_SIZE(AI_ARRAY_GET_BYTE_SIZE(AI_ARRAY_OBJ_FMT(array_), \ - AI_ARRAY_OBJ_SIZE(array_))) - -#define AI_ARRAY_OBJ_DATA_SIZE(array_) \ - AI_ARRAY_GET_DATA_BYTE_SIZE(AI_ARRAY_OBJ_FMT(array_), \ - AI_ARRAY_OBJ_SIZE(array_)) - -#define AI_ARRAY_OBJ_DATA(array_, type_) \ - ((type_*)(AI_ARRAY_OBJ(array_)->data)) - -#define AI_ARRAY_OBJ_DATA_START(array_, type_) \ - ((type_*)(AI_ARRAY_OBJ(array_)->data_start)) - -#define AI_ARRAY_OBJ_ELEM(array_, type_, pos_) \ - AI_ARRAY_OBJ_DATA(array_, type_)[(pos_)] - -#define AI_ARRAY_OBJ_INIT_STATIC(type_, format_, size_, ...) { \ - .format = AI_FMT_OBJ(format_), \ - .size = (ai_array_size)(size_), \ - .data = (ai_ptr)((type_[]){ __VA_ARGS__ }), \ - .data_start = AI_PTR(0), \ -} - -#define AI_ARRAY_OBJ_INIT(format_, data_, data_start_, size_) { \ - .format = AI_FMT_OBJ(format_), \ - .size = (ai_array_size)(size_), \ - .data = AI_PTR(data_), \ - .data_start = AI_PTR(data_start_) } - -#define AI_ARRAY_OBJ_DECLARE_STATIC(name_, type_, format_, attr_, size_, ...) \ - AI_ALIGNED(4) \ - attr_ ai_array name_ = AI_ARRAY_OBJ_INIT_STATIC(type_, format_, size_, __VA_ARGS__); - - -#define AI_ARRAY_OBJ_DECLARE(name_, format_, data_, data_start_, size_, attr_) \ - AI_ALIGNED(4) \ - attr_ ai_array name_ = AI_ARRAY_OBJ_INIT(format_, data_, data_start_, size_); - - -/********************************* ai_array macros ***************************/ -#define AI_PACK_ARRAYS(...) \ - (ai_array[]) { AI_PACK(__VA_ARGS__) } - -#define AI_ARRAY_LIST_OBJ_INIT(arrays_ptr_) \ - ((ai_array*)(arrays_ptr_)) - -#define AI_ARRAY_LIST_FLAGS(list_) \ - ( (list_) ? (list_)->flags : 0x0 ) - -#define AI_ARRAY_LIST_SIZE(list_) \ - ( (list_) ? (list_)->size : 0 ) - -#define AI_ARRAY_LIST_DATA(list_, pos_) \ - ( (list_) ? &((list_)->data[pos_]) : NULL ) - - -/********************************* ai_tensor macros **************************/ -#define AI_TENSOR_OBJ(obj_) \ - ((ai_tensor*)(obj_)) - -#define AI_TENSOR_INFO_OBJ_INIT(id_, flags_, data_size_) { \ - .id = (id_), \ - .flags = (flags_), \ - .data_size = (data_size_) \ -} - -#define AI_TENSOR_OBJ_INIT(id_, flags_, shape_, stride_, arrays_size_, arrays_ptr_, klass_obj_) { \ - .klass = (ai_klass_obj)(klass_obj_), \ - .info = AI_TENSOR_INFO_OBJ_INIT(id_, flags_, arrays_size_), \ - .shape = shape_, \ - .stride = stride_, \ - .data = AI_ARRAY_LIST_OBJ_INIT(AI_PACK(arrays_ptr_)), \ -} - -#define AI_TENSOR_OBJ_DECLARE(name_, attr_, id_, flags_, shape_, stride_, \ - arrays_size_, arrays_ptr_, klass_obj_) \ - AI_ALIGNED(4) \ - attr_ ai_tensor name_ = AI_TENSOR_OBJ_INIT(id_, flags_, AI_PACK(shape_), AI_PACK(stride_), \ - arrays_size_, AI_PACK(arrays_ptr_), AI_PACK(klass_obj_)); - -/********************************* TENSOR STATE MACROS ***********************/ -#define AI_TENSOR_STATE_OBJ_INIT(end_ptr_ , curr_ptr_, stride_, size_) \ - { (end_ptr_), (curr_ptr_), (stride_), (size_) } - -/********************************* TENSOR LIST MACROS ************************/ -#define AI_TENSOR_LIST_EMPTY \ - { .size = 0, .flags = AI_FLAG_NONE, \ - .tensor = (ai_tensor*[]) { NULL }, .info = NULL \ - } - -#define AI_TENSOR_LIST_ENTRY(...) \ - { .size = AI_NUMARGS(__VA_ARGS__), .flags = AI_FLAG_NONE, \ - .tensor = (ai_tensor*[]) { __VA_ARGS__ }, .info = NULL \ - } - -#define AI_TENSOR_LIST_OBJ_DECLARE(name_, attr_, ...) \ - AI_ALIGNED(4) \ - attr_ ai_tensor_list name_ = AI_TENSOR_LIST_ENTRY(__VA_ARGS__); - -/********************************* TENSOR LIST I/O MACROS ********************/ -#define AI_TENSOR_LIST_IO_ENTRY(flags_, size_, ...) \ - { .size = (size_), .flags = (flags_), \ - .tensor = (ai_tensor*[]) { __VA_ARGS__ }, \ - .info = (ai_tensor_list_info[1]) { { \ - .buffer = (ai_buffer[size_])AI_STRUCT_INIT, \ - .state = (ai_tensor_state[size_])AI_STRUCT_INIT, \ - .meta = (ai_buffer_meta_info[size_])AI_STRUCT_INIT \ - } } \ - } - -/********************************* TENSOR CHAIN MACROS ***********************/ -#define AI_TENSOR_CHAIN_OBJ_INIT(flags_, size_, ...) \ - { .size = (size_), .flags = (flags_), \ - .chain = (ai_tensor_list[]){ __VA_ARGS__ } } - -#define AI_TENSOR_CHAIN_OBJ_DECLARE(name_, attr_, size_, ...) \ - AI_ALIGNED(4) \ - attr_ ai_tensor_chain name_ = \ - AI_TENSOR_CHAIN_OBJ_INIT(AI_FLAG_NONE, size_, __VA_ARGS__); - - -/********************************* TENSOR CHAIN I/O MACROS *******************/ -#define AI_TENSOR_CHAIN_IO_OBJ_INIT(flags_, in_tensor_list_, out_tensor_list_) \ - { .chain = (ai_tensor_list[]){ in_tensor_list_, out_tensor_list_ }, \ - .size = 2, .flags = (flags_) } - -#define AI_TENSOR_CHAIN_IO_OBJ_DECLARE( \ - name_, attr_, flags_, in_tensor_list_, out_tensor_list_) \ - AI_ALIGNED(4) \ - attr_ ai_tensor_chain_io name_ = \ - AI_TENSOR_CHAIN_IO_OBJ_INIT(flags_, in_tensor_list_, out_tensor_list_); - -/******************************* NETWORK SECTION ****************************/ -#define AI_NETWORK_OBJ(obj_) \ - ((ai_network*)(obj_)) - - -#define AI_NETWORK_OBJ_INIT( \ - weights_buffer_, activations_buffer_, \ - in_tensor_list_ptr_, out_tensor_list_ptr_, \ - in_node_ptr_, signature_, klass_obj_) { \ - .magic = 0x0, \ - .signature = signature_, \ - .klass = AI_KLASS_OBJ(klass_obj_), \ - .flags = AI_FLAG_NONE, \ - .error = AI_ERROR_INIT(NONE, NONE), \ - .n_batches = 0, \ - .batch_id = 0, \ - .params = weights_buffer_, \ - .activations = activations_buffer_, \ - .tensors = AI_TENSOR_CHAIN_IO_OBJ_INIT(AI_FLAG_NONE, \ - AI_PACK(in_tensor_list_ptr_), \ - AI_PACK(out_tensor_list_ptr_)), \ - .input_node = AI_NODE_OBJ(in_node_ptr_), \ - .current_node = AI_NODE_OBJ(NULL), \ -} - -#define AI_NETWORK_OBJ_DECLARE( \ - name_, attr_, \ - weights_buffer_, activations_buffer_, \ - in_tensor_list_ptr_, out_tensor_list_ptr_, \ - in_node_ptr_, signature_, klass_obj_) \ - AI_ALIGNED(4) \ - attr_ ai_network name_ = AI_NETWORK_OBJ_INIT( \ - AI_PACK(weights_buffer_), \ - AI_PACK(activations_buffer_), \ - AI_PACK(in_tensor_list_ptr_), \ - AI_PACK(out_tensor_list_ptr_), \ - (in_node_ptr_), (signature_), (klass_obj_)); - -#define AI_NETWORK_ACQUIRE_CTX(handle_) \ - AI_NETWORK_OBJ(ai_platform_context_acquire(handle_)) - - -/******************************************************************************/ -AI_API_DECLARE_BEGIN - -/*! - * @typedef ai_klass_obj - * @ingroup ai_platform_interface - * @brief handler to (private) generic subclass derivatives implementation - */ -typedef void* ai_klass_obj; - -/*! - * @typedef ai_ptr - * @ingroup ai_platform_interface - * @brief Byte pointer data addressing - */ -typedef uint8_t* ai_ptr; - -/*! - * @typedef ai_ptr_const - * @ingroup ai_platform_interface - * @brief Constant byte pointer data addressing - */ -typedef const uint8_t* ai_ptr_const; - -/*! - * @typedef ai_ptr_offset - * @ingroup ai_platform_interface - * @brief byte offset for computing strides - */ -typedef int32_t ai_ptr_offset; - -/*! - * @typedef ai_flags - * @ingroup ai_platform_interface - * @brief bitmask for flags management - */ -typedef uint32_t ai_flags; - -/*! - * @typedef ai_magic - * @ingroup ai_platform_interface - * @brief magic field to mark internal datatstructures - */ -typedef uint32_t ai_magic; - - -#define AI_CONTEXT_FIELDS \ - ai_magic magic; /*!< magic word to mark valid contexts datastructs*/ \ - ai_signature signature; /*!< 32bit signature for network consistency checks */ - -#define AI_CONTEXT_OBJ(obj) ((ai_context*)(obj)) - -/*! - * @typedef ai_context - * @ingroup ai_platform_interface - * @brief Abstract internal context header exposed to codegen interface - */ -AI_PACKED_STRUCT_START -typedef AI_ALIGNED_TYPE(struct, 4) AI_PACKED ai_context_ { - AI_CONTEXT_FIELDS -} ai_context; -AI_PACKED_STRUCT_END - -/*! - * @enum ai_shape_2d_type - * @ingroup ai_platform_interface - * @brief Codes for the 2D tensor dimensions - */ -typedef enum { - AI_SHAPE_2D_MAX_DIMENSION = 0x2, - AI_SHAPE_2D_HEIGHT = 0x1, - AI_SHAPE_2D_WIDTH = 0x0, -} ai_shape_2d_type; - - -/*! - * @struct ai_shape_2d - * @ingroup ai_platform_interface - * @brief Dimensions for generic 2D tensors - */ -AI_PACKED_STRUCT_START -typedef AI_ALIGNED_TYPE(struct, 4) AI_PACKED ai_shape_2d_s { - ai_shape_dimension data[AI_SHAPE_2D_MAX_DIMENSION]; /*!< 2D tensor dimensions */ -} ai_shape_2d; -AI_PACKED_STRUCT_END - - -/*! - * @struct ai_array - * @ingroup ai_platform_interface - * @brief Generic flattened array with size - * and (byte) stride of each item - */ -AI_PACKED_STRUCT_START -typedef AI_ALIGNED_TYPE(struct, 4) AI_PACKED ai_array_s { -// ai_u16 flags; /*!< optional flags to store array list attributes */ -// ai_u16 id; /*!< ID of the array object */ - ai_array_format format; /*!< array format (see @ref ai_array_format) */ - ai_array_size size; /*!< number of elements in the array (NOT number - of bytes!). The size of the array could be - determine using @ref AI_ARRAY_GET_BYTE_SIZE - macro */ - ai_ptr data; /*!< pointer to data */ - ai_ptr data_start; /*!< pointer to parent's data start address */ -} ai_array; -AI_PACKED_STRUCT_END - -/*! - * @struct ai_tensor_info - * @ingroup ai_platform_interface - * @brief ai_tensor_info info structure for storing size of the array list, - * tensor dimensionality, etc. - * - */ -AI_PACKED_STRUCT_START -typedef AI_ALIGNED_TYPE(struct, 4) AI_PACKED ai_tensor_info_s { - ai_u16 id; - ai_u8 flags; - ai_u8 data_size; -} ai_tensor_info; -AI_PACKED_STRUCT_END - -/*! - * @struct ai_tensor - * @ingroup ai_platform_interface - * @brief Generic tensor structure for storing parameters and activations - * - * The data is stored in a flattened array with an implicit order given by the - * reverse order in @ref ai_shape_dimension: - * in_channels, channels, width, height. - */ -AI_PACKED_STRUCT_START -typedef AI_ALIGNED_TYPE(struct, 4) AI_PACKED ai_tensor_s { - ai_klass_obj klass; /*!< opaque pointer to klass context */ - ai_tensor_info info; /*!< tensor info metadata see @ref ai_tensor_info)*/ - ai_shape shape; /*!< tensor shape see @ref ai_shape */ - ai_stride stride; /*!< tensor stride see @ref ai_stride */ - ai_array* data; /*!< flattened array pointer to tensor data */ -} ai_tensor; -AI_PACKED_STRUCT_END - -/*! - * @struct ai_tensor_state - * @ingroup ai_platform_interface - * @brief state context for tensor management (used for I/O network tensors) - */ -AI_PACKED_STRUCT_START -typedef AI_ALIGNED_TYPE(struct, 4) AI_PACKED ai_tensor_state_s { - ai_ptr end_ptr; /*!< end address of the I/O tensor data buffer */ - ai_ptr curr_ptr; /*!< current address of the I/O tensor data buffer (for batching) */ - ai_ptr_offset stride; /*!< single batch buffer size (in bytes) */ - ai_size size; /*!< total size in bytes of the I/O tensor buffer */ -} ai_tensor_state; -AI_PACKED_STRUCT_END - -/*! - * @struct ai_tensor_list_info - * @ingroup ai_platform_interface - * @brief info metadata for tensor list management (used for I/O network tensors) - */ -AI_PACKED_STRUCT_START -typedef AI_ALIGNED_TYPE(struct, 4) AI_PACKED ai_tensor_list_info_s { - ai_tensor_state* state; /*!< I/O buffer internal pointers state */ - ai_buffer* buffer; /*!< I/O buffer pointer */ - ai_buffer_meta_info* meta; /*!< I/O buffer meta informations */ -} ai_tensor_list_info; -AI_PACKED_STRUCT_END - -/********************************* INTEGER QUANTIZATION DATATYPES ************/ - -#define AI_INTQ_INFO_OBJ_INIT(flags_, scale_ , zeropoint_) { \ - .scale = (scale_), \ - .zeropoint = (ai_handle)(zeropoint_), \ - .flags = (flags_), \ -} - - -#define AI_PACK_INTQ_INFO_LIST(...) \ - (ai_intq_info_list[]) { AI_PACK(__VA_ARGS__) } - -#define AI_PACK_INTQ_INFO(scale_, zp_) \ - (ai_intq_info[1]) { { .scale = AI_PACK(scale_), \ - .zeropoint = AI_PACK(zp_) } } - -#define AI_PACK_INTQ_SCALE(...) \ - (ai_float[]) { AI_PACK(__VA_ARGS__) } - -#define AI_PACK_INTQ_ZP(...) \ - (ai_i8[]) { AI_PACK(__VA_ARGS__) } - -#define AI_PACK_UINTQ_ZP(...) \ - (ai_u8[]) { AI_PACK(__VA_ARGS__) } - - -#define AI_INTQ_INFO_LIST_OBJ_EMPTY { 0 } - -#define AI_INTQ_INFO_LIST_OBJ_INIT(flags_, size_, info_) \ -{ \ - .flags = (flags_), \ - .size = (size_), \ - .info = (info_), \ -} - -#define AI_INTQ_INFO_LIST_OBJ_DECLARE(name_, attr_, ...) \ - AI_ALIGNED(4) \ - attr_ ai_intq_info_list name_ = \ - AI_INTQ_INFO_LIST_OBJ_INIT(AI_FLAG_NONE, __VA_ARGS__); - - -/********************************* TENSOR CHAINS DATATYPES *******************/ -/*! - * @enum ai_tensor_chain_type - * @ingroup ai_platform_interface - * @brief Enum for the different tensor chains supported in the library - */ -typedef enum { - AI_TENSOR_CHAIN_INPUT = 0x0, - AI_TENSOR_CHAIN_OUTPUT = 0x1, - AI_TENSOR_CHAIN_WEIGHTS = 0x2, - AI_TENSOR_CHAIN_SCRATCH = 0x3, - AI_TENSOR_CHAIN_SIZE -} ai_tensor_chain_type; - -/*! - * @struct ai_tensor_list - * @ingroup ai_platform_interface - * @brief list (in form of arrays) of internal nodes tensor pointers - */ -AI_PACKED_STRUCT_START -typedef AI_ALIGNED_TYPE(struct, 4) AI_PACKED ai_tensor_list_s { - ai_u16 size; /*!< number of elements in the the tensor list */ - ai_u16 flags; /*!< optional flags to store tensor list attributes */ - ai_tensor** tensor; /*!< array of linked tensor pointer */ - ai_tensor_list_info* info; /*!< pointer to an array of metainfo associated to the tensors */ -} ai_tensor_list; -AI_PACKED_STRUCT_END - - -/*! - * @struct ai_tensor_chain - * @ingroup ai_platform_interface - * @brief tensor chain datastruct for internal network nodes - */ -AI_PACKED_STRUCT_START -typedef AI_ALIGNED_TYPE(struct, 4) AI_PACKED ai_tensor_chain_s { - ai_u16 size; - ai_u16 flags; - ai_tensor_list* chain; /*!< pointer to a 4 sized array see @ref ai_tensor_chain_type */ -} ai_tensor_chain; -AI_PACKED_STRUCT_END - -/* forward function */ -struct ai_node_s; - -/*! - * @struct ai_network - * @ingroup layers - * @brief Structure encoding a sequential neural network - */ -AI_PACKED_STRUCT_START -typedef AI_ALIGNED_TYPE(struct, 4) AI_PACKED ai_network_s { - AI_CONTEXT_FIELDS - ai_klass_obj klass; /*!< opaque handler to specific network implementations */ - ai_flags flags; /*!< bitflags mask to track some network state info */ - ai_error error; /*!< track 1st error code in the network */ - - ai_u16 n_batches; /*!< number of batches to process */ - ai_u16 batch_id; /*!< current batch to to process btw [0, n_batches)*/ - ai_buffer params; /*!< params buffer data */ - ai_buffer activations; /*!< activations buffer data */ - - ai_tensor_chain tensors; /*!< I/O tensor chain list see @ref ai_tensor_list */ - - struct ai_node_s* input_node; /*!< first node to execute */ - struct ai_node_s* current_node; /*!< current node to execute */ -} ai_network; -AI_PACKED_STRUCT_END - -/*! - * @brief Get platform runtime lib revision version as string. - * @ingroup ai_platform_interface - * @return a string containing the revision of the runtime library - */ -AI_INTERFACE_TYPE -const char* ai_platform_runtime_get_revision(void); - -/*! - * @brief Get platform runtime lib version as datastruct. - * @ingroup ai_platform_interface - * @return a datastruct containing the version of the runtime library - */ -AI_INTERFACE_TYPE -ai_platform_version ai_platform_runtime_get_version(void); - -/*! - * @brief Get platform public APIs version as datastruct. - * @ingroup ai_platform_interface - * @return a datastruct containing the version of the public APIs - */ -AI_INTERFACE_TYPE -ai_platform_version ai_platform_api_get_version(void); - -/*! - * @brief Get platform interface private APIs version as datastruct. - * @ingroup ai_platform_interface - * @return a datastruct containing the version of the interface private APIs - */ -AI_INTERFACE_TYPE -ai_platform_version ai_platform_interface_api_get_version(void); - -/*! - * @brief Get platform context. - * @ingroup ai_platform_interface - * @return a valid context handle or NULL otherwise - */ -AI_INTERFACE_TYPE -ai_context* ai_platform_context_acquire(const ai_handle handle); - -/*! - * @brief Release platform context. - * @ingroup ai_platform_interface - * @return an opaque handle to the released object - */ -AI_INTERFACE_TYPE -ai_handle ai_platform_context_release(ai_context* ctx); - - -/*! - * @brief get **first** error tracked when using the network - * @ingroup ai_platform_interface - * @param network an opaque handler to the network context - * @return ai_error the FIRST error generated during network processing - */ -AI_INTERFACE_TYPE -ai_error ai_platform_network_get_error(ai_handle network); - - -/*! - * @brief Set specific error code of the network. if an error is already present - * keep it - * @ingroup ai_platform_interface - * @param net_ctx a pointer to the network context - * @param type error type as defined in @ref ai_error_type - * @param code error code as defined in @ref ai_error_code - * @return true if no previous errors where recorded, false if a previous error - * is present or context is invalid - */ -AI_INTERFACE_TYPE -ai_bool ai_platform_network_set_error( - ai_network* net_ctx, const ai_error_type type, const ai_error_code code); - -/*! - * @brief Finalize network report datastruct with I/O buffer infos - * @ingroup ai_platform_interface - * @return bool if the report has been finalized correctly. false otherwise - */ -AI_INTERFACE_TYPE -ai_bool ai_platform_api_get_network_report( - ai_handle network, ai_network_report* r); - -/*! - * @brief create a network context with some error check - * @ingroup ai_platform_interface - * @param a pointer to an opaque handle of the network context - * @param an (optional) pointer to the network config buffer info - * @param net_ctx a pointer to the network context structure to initialize - * @param tools_major major version id of the tool used to generate the network - * @param tools_minor minor version id of the tool used to generate the network - * @param tools_micro micro version id of the tool used to generate the network - * @return the error during network creation or error none if ok - */ -AI_INTERFACE_TYPE -ai_error ai_platform_network_create( - ai_handle* network, const ai_buffer* network_config, - ai_network* net_ctx, - const ai_u8 tools_major, const ai_u8 tools_minor, const ai_u8 tools_micro); - -/*! - * @brief destroy a network context - * @ingroup ai_platform_interface - * @param network a pointer to an opaque handle of the network context - * @return AI_HANDLE_NULL if deallocation OK, same network handle if failed - */ -AI_INTERFACE_TYPE -ai_handle ai_platform_network_destroy(ai_handle network); - -/*! - * @brief initialize the network context - * @ingroup ai_platform_interface - * @param network a pointer to an opaque handle of the network context - * @return a valid network context, NULL if initialization failed - */ -AI_INTERFACE_TYPE -ai_network* ai_platform_network_init( - ai_handle network, const ai_network_params* params); - -/*! - * @brief main platform runtime execute of a network - * @ingroup ai_platform_interface - * @param network an opaque handler to the network context - * @param input a pointer to the input buffer data to process - * @param output a pointer to the output buffer - * @return the number of batches processed from the input. A result <=0 in case - * of error - */ -AI_INTERFACE_TYPE -ai_i32 ai_platform_network_process( - ai_handle network, const ai_buffer* input, ai_buffer* output); - -AI_API_DECLARE_END - -#endif /*__AI_PLATFORM_INTERFACE_H__*/ diff --git a/src/stm32cubeai/AI/Inc/core_common.h b/src/stm32cubeai/AI/Inc/core_common.h deleted file mode 100755 index 5737189f2..000000000 --- a/src/stm32cubeai/AI/Inc/core_common.h +++ /dev/null @@ -1,291 +0,0 @@ -/** - ****************************************************************************** - * @file core_common.h - * @author AST Embedded Analytics Research Platform - * @date 20-Lug-2018 - * @brief header file of common core datatypes - ****************************************************************************** - * @attention - * - *

© Copyright (c) 2018 STMicroelectronics. - * All rights reserved.

- * - * This software component is licensed by ST under Ultimate Liberty license - * SLA0044, the "License"; You may not use this file except in compliance with - * the License. You may obtain a copy of the License at: - * www.st.com/SLA0044 - * - ****************************************************************************** - */ - -#ifndef __CORE_COMMON_H_ -#define __CORE_COMMON_H_ -#pragma once - -#include "ai_platform.h" -#include "ai_platform_interface.h" -#include "ai_datatypes_internal.h" -#include "core_datatypes.h" -#include "core_log.h" - -/*! - * @defgroup core_common Common Core Library Routines - * @brief Common macros, datatypes and routines of core common module - * @details This module contains the definitons and handling of the @ref ai_node - * datastructures. An ai_node is a generic abstraction for a network node that - * could be either a fixed function layer or an operator. Ideally the platform - * interface defined in api module should handle an process generic nodes in the - * network, not relying on the fact that they are layers or operators datastructs - * Specific implementative details should be kept inside layers and operators - * modules. The core module implements additionally common routines used in the - * layers and operators modules. - */ - -/******************************************************************************/ -#ifdef HAS_AI_ASSERT - #define ASSERT_ARRAY_SANITY(a_) \ - AI_ASSERT((a_) && (a_)->size>0) - - #define ASSERT_ARRAY_DATA_SANITY(a_) \ - ASSERT_ARRAY_SANITY(a_) \ - AI_ASSERT((a_)->data && (a_)->data_start) - - #define ASSERT_TENSOR_SANITY(t_) \ - AI_ASSERT((t_) && (t_)->data) \ - AI_ASSERT(CORE_TENSOR_GET_SHAPE_SIZE(t_)>0) \ - ASSERT_ARRAY_SANITY((t_)->data) - - #define ASSERT_TENSOR_LIST_SANITY(tlist_) \ - AI_ASSERT((tlist_) && (GET_TENSOR_LIST_SIZE(tlist_)>0)) \ - - #define ASSERT_TENSOR_DATA_SANITY(t_) \ - ASSERT_TENSOR_SANITY(t_) \ - ASSERT_ARRAY_DATA_SANITY((t_)->data) - - #define ASSERT_NODE_SANITY(node_) \ - do { \ - AI_ASSERT(AI_NODE_OBJ(node_)->tensors && AI_NODE_OBJ(node_)->tensors->chain) \ - ASSERT_TENSOR_SANITY(GET_TENSOR_IN(AI_NODE_OBJ(node_)->tensors, 0)) \ - ASSERT_TENSOR_SANITY(GET_TENSOR_OUT(AI_NODE_OBJ(node_)->tensors, 0)) \ - } while (0); -#else - #define ASSERT_ARRAY_SANITY(a_) /* ASSERT_ARRAY_SANITY */ - #define ASSERT_ARRAY_DATA_SANITY(a_) /* ASSERT_ARRAY_DATA_SANITY */ - #define ASSERT_TENSOR_SANITY(t_) /* ASSERT_TENSOR_SANITY */ - #define ASSERT_TENSOR_LIST_SANITY(tlist_) /* ASSERT_TENSOR_LIST_SANITY */ - #define ASSERT_TENSOR_DATA_SANITY(t_) /* ASSERT_TENSOR_DATA_SANITY */ - #define ASSERT_NODE_SANITY(node_) /* ASSERT_NODE_SANITY */ -#endif /*HAS_AI_ASSERT*/ - - -#if defined(__GNUC__) || defined(__clang__) - /* Suppress unused function warnings */ - #define AI_UNUSED_FUNCTION __attribute__((unused)) - /* Manage false positives in address sanitizer */ - #define AI_NO_SANITIZE_ADDRESS __attribute__((no_sanitize_address)) -#else - #define AI_UNUSED_FUNCTION /* AI_UNUSED_FUNCTION */ - #define AI_NO_SANITIZE_ADDRESS /* AI_NO_SANITIZE_ADDRESS */ -#endif - - -/******************************************************************************/ -#define AI_NODE_TYPE(type_) \ - ( (ai_node_type)((ai_u32)(type_)&0xFFFF) ) - -#define AI_NODE_OBJ(obj_) \ - ((ai_node*)(obj_)) - -#define AI_NODE_FORWARD_FUNC(func_) \ - ((node_forward_func)(func_)) - -#define AI_NODE_IS_FIRST(node) \ - (AI_NODE_OBJ(node)==AI_NODE_OBJ(AI_NODE_OBJ(node)->network->input_node)) - -#define AI_NODE_IS_LAST(node_) \ - ((AI_NODE_OBJ(node_)==AI_NODE_OBJ(node_)->next) || \ - (AI_NODE_OBJ(node_)->next==NULL)) - -#define AI_NODE_COMMON_FIELDS_DECLARE \ - ai_node_type type; /*!< node type id (see @ref ai_node_type) */ \ - ai_id_obj id; /*!< node object instance id (see @ref ai_id_obj) */ \ - ai_klass_obj klass; /*!< opaque handler to specific layer implementations */ \ - struct ai_network_s* network; /*!< handle to global network context */ \ - struct ai_node_s* next; /*!< the next node object in the sequence */ \ - node_forward_func forward; /*!< forward function for the node */ \ - AI_CONST ai_tensor_chain* tensors; /*!< pointer to node tensor chain */ - -#define AI_NODE_COMMON_INIT(type_, id_, forward_, next_, network_, klass_obj_) \ - .type = AI_NODE_TYPE(type_), \ - .id = AI_ID_OBJ(id_), \ - .klass = AI_KLASS_OBJ(klass_obj_), \ - .network = AI_NETWORK_OBJ(network_), \ - .next = AI_NODE_OBJ(next_), \ - .forward = AI_NODE_FORWARD_FUNC(forward_), \ - .tensors = NULL - -#define AI_FOR_EACH_NODE_DO(node_, nodes_) \ - for ( ai_node* node_ = AI_NODE_OBJ(nodes_); (node_); \ - node_ = ((AI_NODE_IS_LAST(node_)) ? NULL : (node_)->next) ) - - -/** TENSOR CHAINS LOOP MACROS & GETTERS *************************************/ -#define AI_FOR_EACH_TENSOR_CHAIN_DO(tlist_ptr_, chain_) \ - ai_tensor_list* tlist_ptr_ = (chain_)->chain; \ - for ( ; tlist_ptr_<(((chain_)->chain)+((chain_)->size)); tlist_ptr_++ ) - -#define AI_FOR_EACH_TENSOR_LIST_DO(idx_, t_ptr_, tlist_ptr_) \ - ai_tensor* t_ptr_ = (GET_TENSOR_LIST_SIZE(tlist_ptr_)>0) \ - ? GET_TENSOR_LIST_ITEM(tlist_ptr_, 0) : NULL; \ - for ( ai_size idx_ = 0; \ - idx_ < GET_TENSOR_LIST_SIZE(tlist_ptr_) && \ - (t_ptr_ = GET_TENSOR_LIST_ITEM(tlist_ptr_, idx_)) != 0; ++idx_) - -#define GET_TENSOR_LIST_INFO(list_) \ - ( (list_)->info ) - -#define GET_TENSOR_LIST_META(list_, pos_) \ - ( &(GET_TENSOR_LIST_INFO(list_)->meta[pos_]) ) - -#define GET_TENSOR_LIST_STATE(list_, pos_) \ - ( &(GET_TENSOR_LIST_INFO(list_)->state[pos_]) ) - -#define GET_TENSOR_LIST_BUFFER(list_, pos_) \ - ( &(GET_TENSOR_LIST_INFO(list_)->buffer[pos_]) ) - -#define GET_TENSOR_LIST_ITEM(list_, pos_) \ - ( (NULL!=(list_)->tensor) \ - ? (list_)->tensor[(pos_)] : NULL ) - -#define GET_TENSOR_LIST_ITEMS(list_) \ - ( (list_)->tensor ) - -#define GET_TENSOR_LIST_SIZE(list_) \ - ( (NULL!=(list_)) ? (list_)->size : 0 ) - -#define GET_TENSOR_CHAIN_SIZE(chain_) \ - ( (NULL!=(chain_)) ? (chain_)->size : 0 ) - -#define GET_TENSOR_LIST(chain_, type_) \ - ( (AI_CONCAT(AI_TENSOR_CHAIN_, type_)<(chain_)->size) \ - ? &(chain_)->chain[AI_CONCAT(AI_TENSOR_CHAIN_, type_)] : NULL ) - -#define GET_TENSOR_LIST_IN(chain_) \ - ( GET_TENSOR_LIST(chain_, INPUT) ) - -#define GET_TENSOR_LIST_OUT(chain_) \ - ( GET_TENSOR_LIST(chain_, OUTPUT) ) - -#define GET_TENSOR_LIST_WEIGTHS(chain_) \ - ( GET_TENSOR_LIST(chain_, WEIGHTS) ) - -#define GET_TENSOR_LIST_SCRATCH(chain_) \ - ( GET_TENSOR_LIST(chain_, SCRATCH) ) - -#define GET_TENSOR_IN(chain_, pos_) \ - ( GET_TENSOR_LIST_ITEM(GET_TENSOR_LIST_IN(chain_), (pos_)) ) - -#define GET_TENSOR_OUT(chain_, pos_) \ - ( GET_TENSOR_LIST_ITEM(GET_TENSOR_LIST_OUT(chain_), (pos_)) ) - -#define SET_TENSOR_IN(chain_, pos_) \ - ( GET_TENSOR_LIST_IN(chain_)->tensor[(pos_)] ) - -#define SET_TENSOR_OUT(chain_, pos_) \ - ( GET_TENSOR_LIST_OUT(chain_)->tensor[(pos_)] ) - -#define GET_TENSOR_WEIGHTS(chain_, pos_) \ - ( GET_TENSOR_LIST_ITEM(GET_TENSOR_LIST_WEIGTHS(chain_), (pos_)) ) - -#define GET_TENSOR_SCRATCH(chain_, pos_) \ - ( GET_TENSOR_LIST_ITEM(GET_TENSOR_LIST_SCRATCH(chain_), (pos_)) ) - -#define AI_NODE_IO_GET(node_, in_, out_) \ - ASSERT_NODE_SANITY(node_) \ - ai_tensor* in_ = GET_TENSOR_IN((node_)->tensors, 0); \ - ai_tensor* out_ = GET_TENSOR_OUT((node_)->tensors, 0); \ - ASSERT_TENSOR_SANITY(in_) \ - ASSERT_TENSOR_SANITY(out_) - -/******************************************************************************/ - -#if 1 - #define SECTION_SERIAL(expr) expr - #define SECTION_PARALLEL(expr) -#else - #define SECTION_SERIAL(expr) - #define SECTION_PARALLEL(expr) expr -#endif - -AI_API_DECLARE_BEGIN - -/*! - * @struct ai_node_type - * @ingroup core_common - * @brief generic network node numeric type ID - * - */ -typedef uint16_t ai_node_type; - -/*! - * @typedef void (*node_forward_func)(struct ai_node_s* node) - * @ingroup core_common - * @brief Callback signatures for all forward functions - */ -typedef void (*node_forward_func)(struct ai_node_s* node); - -/*! - * @typedef ai_float (*func_nl_el)(const ai_float x) - * @ingroup core_common - * @brief Fuction pointer for generic elementwise transforms - * - * This function pointer abstracts a generic nonlinear function applied to a - * single element. See @ref ai_math_sqrt in @ref math_helpers as examples. - */ -typedef ai_float (*func_nl_el)(const ai_float x); - -/*! - * @struct ai_node - * @ingroup core_common - * @brief Structure encoding a generic node of the network - * - * The node struct includes information about the network it belong to, the - * next node in a sequential network and the forward function. The forward - * functions are implemented in the @ref layers module. - */ -typedef AI_ALIGNED_TYPE(struct, 4) ai_node_s { - AI_NODE_COMMON_FIELDS_DECLARE -} ai_node; - -/*! - * @brief initialize core module - * @ingroup core_common - * @return false if initialization fails, false otherwise - */ -AI_INTERNAL_API -ai_bool core_init(void); - -/*! - * @brief get 1st error raised during processing - * @ingroup core_common - * @param[out] error the @ref ai_error recorded during processing - * @return the 1st error generated during processing. If no errors AI_ERROR_NONE - */ -AI_INTERNAL_API -ai_error core_get_error(ai_error* error); - -/*! - * @brief set error recorded during processing - * @ingroup core_common - * @param[out] error the @ref ai_error to set - * @param[in] type the specific error type to set - * @param[in] code the specific error code to set - * @return true if the error is set, false in case a precedent error was already - */ -AI_INTERNAL_API -ai_bool core_set_error( - ai_error* error, const ai_error_type type, const ai_error_code code); - -AI_API_DECLARE_END - -#endif /*__CORE_COMMON_H_*/ diff --git a/src/stm32cubeai/AI/Inc/core_convert.h b/src/stm32cubeai/AI/Inc/core_convert.h deleted file mode 100755 index e48f78b32..000000000 --- a/src/stm32cubeai/AI/Inc/core_convert.h +++ /dev/null @@ -1,72 +0,0 @@ -/** - ****************************************************************************** - * @file core_utils.h - * @author AST Embedded Analytics Research Platform - * @date 16-Aug-2018 - * @brief header file of core utils routines - ****************************************************************************** - * @attention - * - *

© COPYRIGHT(c) 2018 STMicroelectronics

- * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. Neither the name of STMicroelectronics nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - ****************************************************************************** - */ - -#ifndef __CORE_CONVERT_H_ -#define __CORE_CONVERT_H_ -#pragma once - -#include "ai_platform.h" -#include "ai_platform_interface.h" - -#include "core_common.h" - -AI_API_DECLARE_BEGIN - -/*! - * @defgroup core_convert Core Convert Routines - * @brief Implementation of core node format convertion routines (Q7 to float, ... etc.) - */ - - -/*! - * @brief Convert input tensor array from input format to output format - * @ingroup core_convert - * @param[in] pNode in a handler to node (layer or operators) with tensor informations - */ -AI_INTERNAL_API -void node_convert(ai_node *pNode); - -/*! - * @brief Convert a shape struct into a stride struct - * @ingroup core_convert - * @param[in] in a pointer to a shape to convert - * @return a condverted stride datastruct - */ -AI_INTERNAL_API -void core_shape_to_stride(ai_stride* out, const ai_shape* in); - - -#endif /*__CORE_CONVERT_H_*/ diff --git a/src/stm32cubeai/AI/Inc/core_datatypes.h b/src/stm32cubeai/AI/Inc/core_datatypes.h deleted file mode 100755 index e90d57460..000000000 --- a/src/stm32cubeai/AI/Inc/core_datatypes.h +++ /dev/null @@ -1,59 +0,0 @@ -/** - ****************************************************************************** - * @file core_datatypes.h - * @author AST Embedded Analytics Research Platform - * @date 22-Aug-2018 - * @brief header file of core module private defines and datatypes - * to public nor codegen tool - ****************************************************************************** - * @attention - * - *

© Copyright (c) 2018 STMicroelectronics. - * All rights reserved.

- * - * This software component is licensed by ST under Ultimate Liberty license - * SLA0044, the "License"; You may not use this file except in compliance with - * the License. You may obtain a copy of the License at: - * www.st.com/SLA0044 - * - ****************************************************************************** - */ - -#ifndef __AI_CORE_DATATYPES_H_ -#define __AI_CORE_DATATYPES_H_ -#pragma once -#include - -/*! - * @defgroup Core Module Datatypes - * @brief Data structures and defines used by core module - */ - -/*! - * @brief platform runtime core library version - */ -#define AI_PLATFORM_RUNTIME_MAJOR 4 -#define AI_PLATFORM_RUNTIME_MINOR 1 -#define AI_PLATFORM_RUNTIME_MICRO 0 - -#define AI_MAGIC_CONTEXT_TOKEN (0xA1C00100) /*!< AI Cool! Magic Token */ - -#define AI_MAGIC_INSPECTOR_TOKEN (0xA1C00101) /*!< AI Cool! Magic Token */ - - -#define AI_ID_OBJ(id) \ - ((ai_id_obj)(id)) - -#define AI_C_ARRAY_COUNT(array_) \ - ( sizeof(array_) / sizeof((array_)[0]) ) - -/*! - * @typedef ai_id_obj - * @ingroup core_datatypes - * @brief numeric identifier for generic object instances (e.g. layers, - * operators, etc.) It is used by codegen tool to keep tracks of specific - * instances created - */ -typedef uint16_t ai_id_obj; - -#endif /*__AI_CORE_DATATYPES_H_*/ diff --git a/src/stm32cubeai/AI/Inc/core_log.h b/src/stm32cubeai/AI/Inc/core_log.h deleted file mode 100755 index 192a2b298..000000000 --- a/src/stm32cubeai/AI/Inc/core_log.h +++ /dev/null @@ -1,117 +0,0 @@ -/** - ****************************************************************************** - * @file core_log.h - * @author AST Embedded Analytics Research Platform - * @date 14-Aug-2018 - * @brief header file of core log interfaces - ****************************************************************************** - * @attention - * - *

© Copyright (c) 2018 STMicroelectronics. - * All rights reserved.

- * - * This software component is licensed by ST under Ultimate Liberty license - * SLA0044, the "License"; You may not use this file except in compliance with - * the License. You may obtain a copy of the License at: - * www.st.com/SLA0044 - * - ****************************************************************************** - */ - -#ifndef __CORE_LOG_H_ -#define __CORE_LOG_H_ -#pragma once - -#include "ai_platform.h" - -/*! - * @defgroup core_log Logger core routines wrapper interface - * @brief Common macros, datatypes and routines of ai logger module - * @details This header defines the wrapping macros interfaces to handle the - * global logger module. These macro are defined when the macro HAS_LOG is - * defined, otherwise they are all set to NOP routines and no logger code is - * compiled at all. When the macro HAS_LOG is defined, only the log messages - * having an enum id >= the value of the macro are compiled. Thus to include in - * compilation only log messages up to the error level the value of HAS_LOG must - * be equal the the enum value of LOG_ERROR macro (i.e. 3). a value of 6 means - * to include all log messages up to the lower LOG_TRACE level. - */ - -#if defined HAS_LOG && (HAS_LOG>=0) -#include "ai_log.h" - #define AI_LOG_SECTION(...) { __VA_ARGS__ } - - #define AI_LOG_ACQUIRE() \ - ai_log_acquire() - #define AI_LOG_SET_LEVEL(level_) \ - AI_WRAP_FUNC(ai_log_set_level(level_);) - #define AI_LOG_SET_QUIET(onoff_) \ - AI_WRAP_FUNC(ai_log_set_quiet(onoff_);) - #define AI_LOG_SET_LOCK_FN(fn_, udata_) \ - AI_WRAP_FUNC(ai_log_set_lock(fn_, udata_);) - #define AI_LOG_CHANNEL_PUSH(level_, fn_, udata_) \ - AI_WRAP_FUNC(ai_log_channel_push(level_, fn_, udata_);) - #define AI_LOG_CHANNEL_POP(fn_, udata_) \ - AI_WRAP_FUNC(ai_log_channel_pop(fn_, udata_);) - #ifdef LOG_USE_FILE - #define AI_LOG_SET_FILE_POINTER(fp_) \ - AI_WRAP_FUNC(ai_log_set_fp(fp_);) - #else - #define AI_LOG_SET_FILE_POINTER(fp_) \ - /*AI_LOG_SET_FILE_POINTER()*/ - #endif -#else - #define AI_LOG_SECTION(...) /*AI_LOG_SECTION()*/ - - #define AI_LOG_ACQUIRE() (NULL) - #define AI_LOG_SET_LEVEL(level_) /*AI_LOG_SET_LEVEL()*/ - #define AI_LOG_SET_QUIET(onoff_) /*AI_LOG_SET_QUIET()*/ - #define AI_LOG_SET_LOCK_FN(fn_, udata_) /*AI_LOG_SET_LOCK_FN()*/ - #define AI_LOG_CHANNEL_PUSH(level_, fn_, udata_) /*AI_LOG_CHANNEL_PUSH()*/ - #define AI_LOG_CHANNEL_POP(fn_, udata_) /*AI_LOG_CHANNEL_POP()*/ - #define AI_LOG_SET_FILE_POINTER(fp_) /*AI_LOG_SET_FILE_POINTER()*/ -#endif - -#if defined HAS_LOG && (HAS_LOG>=LOG_SUDO) - #define AI_LOG_SUDO(...) AI_WRAP_FUNC(ai_log_log(LOG_SUDO, __FILE__, __LINE__, __VA_ARGS__);) -#else - #define AI_LOG_SUDO(...) /*AI_LOG_SUDO()*/ -#endif - -#if defined HAS_LOG && (HAS_LOG>=LOG_TRACE) - #define AI_LOG_TRACE(...) AI_WRAP_FUNC(ai_log_log(LOG_TRACE, __FILE__, __LINE__, __VA_ARGS__);) -#else - #define AI_LOG_TRACE(...) /*AI_LOG_TRACE()*/ -#endif - -#if defined HAS_LOG && (HAS_LOG>=LOG_DEBUG) - #define AI_LOG_DEBUG(...) AI_WRAP_FUNC(ai_log_log(LOG_DEBUG, __FILE__, __LINE__, __VA_ARGS__);) -#else - #define AI_LOG_DEBUG(...) /*AI_LOG_DEBUG()*/ -#endif - -#if defined HAS_LOG && (HAS_LOG>=LOG_INFO) - #define AI_LOG_INFO(...) AI_WRAP_FUNC(ai_log_log(LOG_INFO, __FILE__, __LINE__, __VA_ARGS__);) -#else - #define AI_LOG_INFO(...) /*AI_LOG_INFO()*/ -#endif - -#if defined HAS_LOG && (HAS_LOG>=LOG_WARN) - #define AI_LOG_WARN(...) AI_WRAP_FUNC(ai_log_log(LOG_WARN, __FILE__, __LINE__, __VA_ARGS__);) -#else - #define AI_LOG_WARN(...) /*AI_LOG_WARN()*/ -#endif - -#if defined HAS_LOG && (HAS_LOG>=LOG_ERROR) - #define AI_LOG_ERROR(...) AI_WRAP_FUNC(ai_log_log(LOG_ERROR, __FILE__, __LINE__, __VA_ARGS__);) -#else - #define AI_LOG_ERROR(...) /*AI_LOG_ERROR()*/ -#endif - -#if defined HAS_LOG && (HAS_LOG>=LOG_FATAL) - #define AI_LOG_FATAL(...) AI_WRAP_FUNC(ai_log_log(LOG_FATAL, __FILE__, __LINE__, __VA_ARGS__);) -#else - #define AI_LOG_FATAL(...) /*AI_LOG_FATAL()*/ -#endif - -#endif /*__CORE_LOG_H_*/ diff --git a/src/stm32cubeai/AI/Inc/core_net_inspect.h b/src/stm32cubeai/AI/Inc/core_net_inspect.h deleted file mode 100755 index b09a1117b..000000000 --- a/src/stm32cubeai/AI/Inc/core_net_inspect.h +++ /dev/null @@ -1,96 +0,0 @@ -/** - ****************************************************************************** - * @file core_net_inspect.h - * @author AST Embedded Analytics Research Platform - * @date 20-Lug-2018 - * @brief header file of core network inspection APIs - ****************************************************************************** - * @attention - * - *

© Copyright (c) 2018 STMicroelectronics. - * All rights reserved.

- * - * This software component is licensed by ST under Ultimate Liberty license - * SLA0044, the "License"; You may not use this file except in compliance with - * the License. You may obtain a copy of the License at: - * www.st.com/SLA0044 - * - ****************************************************************************** - */ - -#ifndef __CORE_NET_INSPECT_H_ -#define __CORE_NET_INSPECT_H_ -#pragma once - -#include "core_net_inspect_interface.h" - -#include "core_common.h" -#include "layers_common.h" - -/*! - * @defgroup core_net_inspect Core Network Inspection routines - * @brief Implementation of core network inspection routines that allows to - * inspect on a node basis a generated network model - * @details A network context @ref ai_network basically contains a chained list - * of nodes @ref ai_node that have an associated forward function. - * Each ai)network context and ai_node datastructs have as a required member - * field an opaque handler (i.e. a void pointer) to a klass object. - * This handler is intended to be used as a platform specific node context - * that implements specific target platform routines. - * The inspector module basically acts as a plugin that exploiting these features - * by temporary creating an hidden inspection context (see - * @ref ai_core_inspect_net_klass) associated to the network and - * linking it by re-routing the klass field to this inspection context. The - * inspection context saves as part of its state (by a stack push operation), the - * internal state of the network (all node / network klass pointers and actual - * forward functions). - * Thus, for each node it re-routes all node's forward functions to a dedicated - * inspection forward function (see @ref _forward_inspect_validate() routine) - * This routine is the core of the mechanism and it allows to inspect a network - * node by node. Some additional inspection could thus be done inside the - * _forward_inspect_validate() routine before and after the actual node - * forward function is called; - * - */ - -AI_API_DECLARE_BEGIN - -/*! - * @defgroup core_net_inspect Network Inspection Core - * @brief Implementation of the validation network routines - */ - -/*! - * @brief Initialize the network inspection context on a given network - * @ingroup core net inspect - * @param network opaque handler to the network instance - * @param cfg a pointer to the inspector configuration we want to use - * @return true if execution of the API is fine, false otherwise - */ -AI_API_ENTRY -ai_bool ai_network_inspect_init( - ai_handle network, const ai_inspect_config* cfg); - -/*! - * @brief Get a summary report from the inspected network - * @ingroup core net inspect - * @param network opaque handler to the network instance - * @param report a pointer to the report provided back by the inspection - * @return true if execution of the API is fine, false otherwise - */ -AI_API_ENTRY -ai_bool ai_network_inspect_get_report( - ai_handle network, ai_inspect_net_report* report); - -/*! - * @brief Destroy the network inspection context on a given network - * @ingroup core net inspect - * @param network opaque handler to the network instance - * @return true if execution of the API is fine, false otherwise - */ -AI_API_ENTRY -ai_bool ai_network_inspect_destroy(ai_handle network); - -AI_API_DECLARE_END - -#endif /*__CORE_NET_INSPECT_H_*/ diff --git a/src/stm32cubeai/AI/Inc/core_net_inspect_interface.h b/src/stm32cubeai/AI/Inc/core_net_inspect_interface.h deleted file mode 100755 index 31b23220a..000000000 --- a/src/stm32cubeai/AI/Inc/core_net_inspect_interface.h +++ /dev/null @@ -1,121 +0,0 @@ -/** - ****************************************************************************** - * @file core_net_inspect_interface.h - * @author AST Embedded Analytics Research Platform - * @date 20-Lug-2018 - * @brief header file of core network inspection interface APIs - ****************************************************************************** - * @attention - * - *

© Copyright (c) 2018 STMicroelectronics. - * All rights reserved.

- * - * This software component is licensed by ST under Ultimate Liberty license - * SLA0044, the "License"; You may not use this file except in compliance with - * the License. You may obtain a copy of the License at: - * www.st.com/SLA0044 - * - ****************************************************************************** - */ - -#ifndef __CORE_NET_INSPECT_INTERFACE_H_ -#define __CORE_NET_INSPECT_INTERFACE_H_ -#pragma once - -#include "ai_platform.h" - -AI_API_DECLARE_BEGIN - -/*! - * @defgroup core_validation Validation Core - * @brief Implementation of the validation network interface headers - */ - - -/*! - * @struct ai_inspect_node_info - * @brief network node inspection context: there is one of this datastruct - * for each node of the network - */ -typedef struct ai_inspect_node_info_s { - ai_u16 type; /*!< node type info @see ai_node datastruct */ - ai_u16 id; /*!< node id assigned by codegen tool to identify - the specific node instance */ - ai_u16 batch_id; /*!< current node batch processed */ - ai_u16 n_batches; /*!< total number of node batches to process */ - ai_float elapsed_ms; /*!< node performance analysys: time in - milliseconds to execute the node forward - function */ - ai_u16 in_size; /*!< number of node's input activation buffers */ - ai_u16 out_size; /*!< number of node's output activation buffers */ - ai_buffer* in; /*!< input node activation buffer see @ref ai_buffer */ - ai_buffer* out; /*!< output node activation buffer see @ref ai_buffer */ -} ai_inspect_node_info; - -/*! - * @struct ai_inspect_net_report - * @brief network inspection report context - */ -typedef struct ai_inspect_net_report_s { - ai_u32 id; /*!< id of the report */ - ai_signature signature; /*!< network identification checksum */ - ai_u32 num_inferences; /*!< total number of inferences processed - during the inspection */ - ai_u32 n_nodes; /*!< number of nodes in the network */ - ai_float elapsed_ms; /*!< network total time (in ms) for processing - num_inferences inferences */ - ai_inspect_node_info* node; /*!< pointer to the array of size n_nodes where - a single node report is reported. see @ref - ai_inspect_node_info datastruct */ -} ai_inspect_net_report; - -/*! - * @enum net inspector inspection mode - * @brief configuration flags to set net inspection mode - */ -typedef enum { - VALIDATION_INSPECT = (0x1<<0), /**< Network validation inspection mode */ - STORE_ALL_IO_ACTIVATIONS = (0x1<<7), /**< Store all I/O activations on snapshot datastruct */ -} ai_inspect_mode; - -typedef enum { - AI_NODE_EXEC_PRE_FORWARD_STAGE = 0x0, - AI_NODE_EXEC_POST_FORWARD_STAGE = 0x1, -} ai_node_exec_stage; - -/*! - * @brief function pointer to callback report - */ -typedef void (*ai_inspect_report_cb_func)( - const ai_handle cookie, - const ai_inspect_net_report* report); - -/*! - * @brief function pointer to node execute - */ -typedef void (*ai_inspect_exec_node_cb_func)( - const ai_handle cookie, - const ai_inspect_node_info* node_info, - const ai_node_exec_stage stage); - -/*! - * @struct ai_inspect_config - * @brief inspection config datastruct - */ -typedef struct ai_inspect_config_s { - ai_u8 validation_mode; /*!< validation mode flags - see @ref ai_inspect_mode */ - ai_u8 log_level; /*!< log class level see @ref LOG_SUDO */ - ai_bool log_quiet; /*!< log class quiet mode */ - ai_inspect_report_cb_func on_report_destroy; /*!< callback function - called when a report datastruct - is released from memory */ - ai_inspect_exec_node_cb_func on_exec_node; /*!< callback function - called when a node is executed (pre & post) */ - ai_handle cookie; -} ai_inspect_config; - - -AI_API_DECLARE_END - -#endif /*__CORE_NET_INSPECT_INTERFACE_H_*/ diff --git a/src/stm32cubeai/AI/Inc/datatypes_network.h b/src/stm32cubeai/AI/Inc/datatypes_network.h deleted file mode 100755 index c10d603f7..000000000 --- a/src/stm32cubeai/AI/Inc/datatypes_network.h +++ /dev/null @@ -1,58 +0,0 @@ -/** - ****************************************************************************** - * @file datatypes_network.h - * @author AST Embedded Analytics Research Platform - * @date 30-Aug-2017 - * @brief Definitions of code generated network types - ****************************************************************************** - * @attention - * - *

© Copyright (c) 2017 STMicroelectronics. - * All rights reserved.

- * - * This software component is licensed by ST under Ultimate Liberty license - * SLA0044, the "License"; You may not use this file except in compliance with - * the License. You may obtain a copy of the License at: - * www.st.com/SLA0044 - * - ****************************************************************************** - */ - -#ifndef __DATATYPES_NETWORK_H__ -#define __DATATYPES_NETWORK_H__ -#pragma once - -/* - * Header to be overriden by the generated version - * by including with <> the include directories are searched in the order - * specified in the compiler - * To enable the override, put the generated path before the API path - */ - -#include "ai_platform.h" - -AI_API_DECLARE_BEGIN - -#ifdef AI_OVERRIDE_CUSTOM_TYPES -#warning "Warning: Custom Types have been already defined!\n" -#endif - -#define AI_CUSTOM_TYPES_COUNT (3) - -#define AI_CUSTOM_TYPES_SIGNATURE_DECLARE(name) \ - const ai_custom_type_signature name[AI_CUSTOM_TYPES_COUNT+1] = { \ - AI_CUSTOM_TYPES_COUNT, \ - AI_CUSTOM_SIZE(ai_shape_dimension), \ - AI_CUSTOM_SIZE(ai_stride_dimension), \ - AI_CUSTOM_SIZE(ai_array_size), \ - }; - - -typedef ai_u32 ai_shape_dimension; -typedef ai_i32 ai_stride_dimension; -typedef ai_u32 ai_array_size; - - -AI_API_DECLARE_END - -#endif /*__DATATYPES_NETWORK_H__*/ diff --git a/src/stm32cubeai/AI/Inc/formats_list.h b/src/stm32cubeai/AI/Inc/formats_list.h deleted file mode 100755 index a0d530f72..000000000 --- a/src/stm32cubeai/AI/Inc/formats_list.h +++ /dev/null @@ -1,69 +0,0 @@ - -/* FMT_ENTRY( exp_(0/1 only), name_, type_id_, - * sign_bit_, float_bit_, pbits_, bits_, fbits_, ldiv_bits_) - * Specifications (in order of the bit fields, little endian): - - name_ : it is the enum used to define both the ai_array_format and - ai_buffer_format. - - exp_ (1bit) : it is a boolean flag (0 or 1) indicating whether the format - is available as a public APIs ai_buffer format. in this case the field - exp_name_ indicates the enum name of the ai_buffer format - - (7 bits): reserved for flags - - sign_bit_ (1bit) : codes whether or not the format is of a signed type - - float_bit_ (1bit) : codes if the format is float - - ldiv_bits (2 bits) : right shift value for computing the byte size of the - format - - type_id_ (4bits) : it is used to define the "family" of the format: - see @ref AI_FMT_Q as an example. Currently supported types are: - AI_FMT_Q (fixed point types), AI_FMT_FLOAT (floating point values), - AI_FMT_LUT4 or AI_FMT_LUT8 (compressed formats) - - pbits_ (3bits) : number of padding bits for the format - - bits_ (7bits) : size in bits of the format (NB: integer+fractional bits) - - fbits_ (7bits) : number of fractional bits for the format (for AI_FMT_Q only) - - */ - -/* Macro tricks are here: - * https://github.com/pfultz2/Cloak/wiki/C-Preprocessor-tricks,-tips,-and-idioms - */ - -/* Format none entry */ -FMT_ENTRY(1, NONE, AI_FMT_NONE, 0, 0, 0, 0, 0, 0) - -/* Floating point formats */ -FMT_ENTRY(1, FLOAT, AI_FMT_FLOAT, 1, 1, 0, 32, 0, 0) -FMT_ENTRY(0, FLOAT64, AI_FMT_FLOAT, 1, 1, 0, 64, 0, 0) -FMT_ENTRY(0, FLOAT16, AI_FMT_FLOAT, 1, 1, 0, 16, 0, 0) - -/* Integer formats (i.e. fractional bits = 0!) */ -FMT_ENTRY(1, U8, AI_FMT_Q, 0, 0, 0, 8, 0, 0) -FMT_ENTRY(1, U16, AI_FMT_Q, 0, 0, 0, 16, 0, 0) -FMT_ENTRY(0, U32, AI_FMT_Q, 0, 0, 0, 32, 0, 0) -FMT_ENTRY(0, U64, AI_FMT_Q, 0, 0, 0, 64, 0, 0) -FMT_ENTRY(0, U4, AI_FMT_Q, 0, 0, 0, 4, 0, 0) - -FMT_ENTRY(1, S8, AI_FMT_Q, 1, 0, 0, 8, 0, 0) -FMT_ENTRY(1, S16, AI_FMT_Q, 1, 0, 0, 16, 0, 0) -FMT_ENTRY(0, S32, AI_FMT_Q, 1, 0, 0, 32, 0, 0) -FMT_ENTRY(0, S64, AI_FMT_Q, 1, 0, 0, 64, 0, 0) -FMT_ENTRY(0, S4, AI_FMT_Q, 1, 0, 0, 4, 0, 0) - -/* Fixed-point formats including ARM CMSIS Q7, Q15, Q31 ones */ -FMT_ENTRY(1, Q, AI_FMT_Q, 1, 0, 0, 0, 0, 0) -FMT_ENTRY(1, Q7, AI_FMT_Q, 1, 0, 0, 8, 7, 0) -FMT_ENTRY(1, Q15, AI_FMT_Q, 1, 0, 0, 16, 15, 0) -FMT_ENTRY(0, Q31, AI_FMT_Q, 1, 0, 0, 32, 31, 0) - -FMT_ENTRY(1, UQ, AI_FMT_Q, 0, 0, 0, 0, 0, 0) -FMT_ENTRY(1, UQ7, AI_FMT_Q, 0, 0, 0, 8, 7, 0) -FMT_ENTRY(1, UQ15, AI_FMT_Q, 0, 0, 0, 16, 15, 0) -FMT_ENTRY(0, UQ31, AI_FMT_Q, 0, 0, 0, 32, 31, 0) - -/* Compressed formats */ -FMT_ENTRY(0, LUT4_FLOAT, AI_FMT_LUT4, 1, 1, 0, 32, 0, 3) -FMT_ENTRY(0, LUT8_FLOAT, AI_FMT_LUT8, 1, 1, 0, 32, 0, 2) -FMT_ENTRY(0, LUT4_Q15, AI_FMT_LUT4, 1, 0, 0, 16, 15, 2) -FMT_ENTRY(0, LUT8_Q15, AI_FMT_LUT8, 1, 0, 0, 16, 15, 1) -FMT_ENTRY(0, LUT4_UQ15, AI_FMT_LUT4, 0, 0, 0, 16, 15, 2) -FMT_ENTRY(0, LUT8_UQ15, AI_FMT_LUT8, 0, 0, 0, 16, 15, 1) - -#undef FMT_ENTRY diff --git a/src/stm32cubeai/AI/Inc/layers.h b/src/stm32cubeai/AI/Inc/layers.h deleted file mode 100755 index d55a10937..000000000 --- a/src/stm32cubeai/AI/Inc/layers.h +++ /dev/null @@ -1,88 +0,0 @@ -/** - ****************************************************************************** - * @file layers.h - * @author AST Embedded Analytics Research Platform - * @date 01-May-2017 - * @brief header file of AI platform layers datatypes - ****************************************************************************** - * @attention - * - *

© Copyright (c) 2017 STMicroelectronics. - * All rights reserved.

- * - * This software component is licensed by ST under Ultimate Liberty license - * SLA0044, the "License"; You may not use this file except in compliance with - * the License. You may obtain a copy of the License at: - * www.st.com/SLA0044 - * - ****************************************************************************** - */ - -#ifndef __LAYERS_H_ -#define __LAYERS_H_ -#pragma once - -#include "layers_common.h" -#include "layers_conv2d.h" -#include "layers_generic.h" -#include "layers_nl.h" -#include "layers_norm.h" -#include "layers_pool.h" -#include "layers_rnn.h" -#include "layers_dense.h" -#include "layers_sm.h" - -#ifdef USE_OPERATORS - #include "layers_lambda.h" -#endif /* USE_OPERATORS */ - - -AI_API_DECLARE_BEGIN - -/*! - * @defgroup layers Layers - * @brief Definition of the forward functions for the layers and the general - * ai_layer datastructure used to abstract specific layer implementation in the - * generic forward function definition - * - * The forward function for a layer computes the layer activations given the - * activations of the previous layer. They are added to the layer as function - * pointer and called implicitly by the @ref ai_layers_forward_all function. - * The input activations are read from layer → in and the computed - * activations stored in layer → out. The layer type needs to be compatible - * with the forward function, but layers with the same layout (e.g. `mp` and - * `ap`) can share the same structure. - */ - -/******************************************************************************/ -/* Forward Functions Section */ -/******************************************************************************/ - -/*! - * @brief Executes a single layer in the network. - * @ingroup layers - * @param layer the layer to process - * @return pointer to the next layer - */ -AI_INTERNAL_API -ai_layer* ai_layers_forward_layer(ai_layer* layer); - - -/*! - * @brief Computes the ouptut of the network given the input. - * @ingroup layers - * - * Given a network with the input pre-loaded in the net → in tensor, - * computes the output by calling the forward functions of each layer and - * selecting the next layer. When the layer has no successor or it's in a - * loop-back configuration (layer → next is again layer), the function - * stops. The result is stored in net → out. - * - * @param net the network to evaluate - */ -AI_INTERNAL_API -void ai_layers_forward_all(ai_network* net); - -AI_API_DECLARE_END - -#endif /* __LAYERS_H_ */ diff --git a/src/stm32cubeai/AI/Inc/layers_common.h b/src/stm32cubeai/AI/Inc/layers_common.h deleted file mode 100755 index 4d66cd296..000000000 --- a/src/stm32cubeai/AI/Inc/layers_common.h +++ /dev/null @@ -1,192 +0,0 @@ -/** - ****************************************************************************** - * @file layers_common.h - * @author AST Embedded Analytics Research Platform - * @date 17-Nov-2017 - * @brief header file of AI platform layers datatypes - ****************************************************************************** - * @attention - * - *

© Copyright (c) 2017 STMicroelectronics. - * All rights reserved.

- * - * This software component is licensed by ST under Ultimate Liberty license - * SLA0044, the "License"; You may not use this file except in compliance with - * the License. You may obtain a copy of the License at: - * www.st.com/SLA0044 - * - ****************************************************************************** - */ - -#ifndef __LAYERS_COMMON_H_ -#define __LAYERS_COMMON_H_ -#pragma once - -#include - -#ifdef USE_CYCLE_MEASUREMENTS - #include "layers_cycles_estimation.h" -#endif -#include "ai_platform.h" -#include "ai_common_config.h" - -#include "core_common.h" -#include "core_convert.h" - -/* optimizations */ -#define AI_OPTIM_DICT8_DOT_ARRAY_F32 (1) -#define AI_OPTIM_DICT8_DTCM (1) -#define AI_OPTIM_FUNC_MP_ARRAY_F32 (0) - - -#define AI_LAYER_OBJ(obj_) \ - ((ai_layer*)(obj_)) - -#define AI_LAYER_FORWARD_FUNC(func_) \ - ((layer_forward_func)(func_)) - -#define AI_LAYER_TYPE(type_) \ - ( (ai_layer_type)((ai_u32)(type_)&0xFFFF) ) - -#define AI_LAYER_TYPE_ENTRY(type_) \ - AI_CONCAT(AI_CONCAT(AI_LAYER_, type_), _TYPE) - -#define AI_LAYER_TYPE_NAME(type_) \ - ai_layer_type_name(AI_LAYER_TYPE(type_)) - -#define AI_LAYER_TYPE_IS_VALID(type_) \ - ai_layer_type_is_valid(AI_LAYER_TYPE(type_)) - -#define AI_LAYER_COMMON_INIT(type_, id_, forward_, next_, network_, klass_) \ - .type = AI_NODE_TYPE(type_), \ - .id = AI_ID_OBJ(id_), \ - .network = AI_NETWORK_OBJ(network_), \ - .next = AI_LAYER_OBJ(next_), \ - .forward = AI_LAYER_FORWARD_FUNC(forward_), \ - .klass = AI_KLASS_OBJ(klass_) - -#define AI_LAYER_OBJ_INIT(type_, id_, network_, next_, forward_, ...) { \ - AI_LAYER_COMMON_INIT(AI_CONCAT(AI_LAYER_, type_), id_, forward_, next_, network_, NULL), \ - ## __VA_ARGS__ } - -#define AI_LAYER_OBJ_DECLARE(varname_, id_, type_, struct_, forward_func_, \ - network_, next_, attr_, ...) \ - AI_ALIGNED(4) \ - attr_ AI_CONCAT(ai_layer_, struct_) varname_ = \ - AI_LAYER_OBJ_INIT( type_, id_, network_, \ - next_, forward_func_, \ - ## __VA_ARGS__ ); - -#define AI_LAYER_IO_GET(layer_, in_, out_) \ - ASSERT_LAYER_SANITY(layer_) \ - const ai_tensor* in_ = GET_TENSOR_IN((layer_)->tensors, 0); \ - ai_tensor* out_ = GET_TENSOR_OUT((layer_)->tensors, 0); \ - ASSERT_TENSOR_DATA_SANITY(in_) \ - ASSERT_TENSOR_DATA_SANITY(out_) - -#define AI_LAYER_LIST_IO_GET(layer_, in_, out_) \ - ASSERT_LAYER_SANITY(layer_) \ - const ai_tensor_list* in_ = GET_TENSOR_LIST_IN((layer_)->tensors); \ - ai_tensor_list* out_ = GET_TENSOR_LIST_OUT((layer_)->tensors); \ - ASSERT_TENSOR_LIST_SANITY(in_) \ - ASSERT_TENSOR_LIST_SANITY(out_) - -#ifdef HAS_AI_ASSERT - #define AI_LAYER_WEIGHTS_GET(layer_, weights_, bias_) \ - const ai_tensor* weights_ = GET_TENSOR_WEIGHTS((layer_)->tensors, 0); \ - const ai_tensor* bias_ = (GET_TENSOR_LIST_SIZE(GET_TENSOR_LIST_WEIGTHS((layer_)->tensors))>1) \ - ? GET_TENSOR_WEIGHTS((layer_)->tensors, 1) \ - : NULL; \ - ASSERT_TENSOR_DATA_SANITY(weights_) \ - if (bias_) { ASSERT_TENSOR_DATA_SANITY(bias_) } -#else - #define AI_LAYER_WEIGHTS_GET(layer_, weights_, bias_) \ - const ai_tensor* weights_ = GET_TENSOR_WEIGHTS((layer_)->tensors, 0); \ - const ai_tensor* bias_ = (GET_TENSOR_LIST_SIZE(GET_TENSOR_LIST_WEIGTHS((layer_)->tensors))>1) \ - ? GET_TENSOR_WEIGHTS((layer_)->tensors, 1) \ - : NULL; \ - -#endif /*HAS_AI_ASSERT*/ - - -AI_API_DECLARE_BEGIN - -/*! - * @defgroup layers_common Layers Common - * @brief Implementation of the common layers datastructures - * This header enumerates the layers specific definition implemented in the - * library toghether with the macros and datatypes used to manipulate them. - */ - -/*! - * @enum ai_layer_type - * @ingroup layers - * @brief ai_tools supported layers type id - */ -typedef enum { -#define LAYER_ENTRY(type_, id_, struct_, forward_func_) \ - AI_LAYER_TYPE_ENTRY(type_) = id_, -#include "layers_list.h" -} ai_layer_type; - -#define AI_LAYER_COMMON_FIELDS_DECLARE \ - AI_NODE_COMMON_FIELDS_DECLARE - -/*! - * @typedef void (*layer_forward_func)(struct ai_layer_* layer) - * @ingroup layers_common - * @brief Callback signatures for all layers forward functions - */ -typedef node_forward_func layer_forward_func; - -/*! - * @struct ai_layer - * @ingroup layers_common - * @brief Structure encoding a layer in the network - * - * The layer struct is an alias for a generic @ref ai_node datastrutcture - */ -typedef ai_node ai_layer; - -/*! - * @struct ai_layer_base - * @ingroup layers_common - * @brief Structure encoding a base layer in the network - * - * The layer_base struct is an alias for a generic @ref ai_layer datastrutcture - */ -typedef ai_layer ai_layer_base; - -/*! - * @brief Check the custom network types against the internally compiled ones - * Helper function to check if the private APIs where compiled with a different - * `datatypes_network.h` than the one provided to the caller. - * @ingroup layers_common - * @param signatures list of type sizes signatures (first element is the number of types) - * @return false if there is a type size mismatch - */ -AI_INTERNAL_API -ai_bool ai_check_custom_types(const ai_custom_type_signature* signatures); - -/*! - * @brief Helper API to retrieve a human readable layer type from enum - * @ingroup layers_common - * @param type in type of layer - * @return string defining the type of the layer - */ -AI_INTERNAL_API -const char* ai_layer_type_name(const ai_layer_type type); - -/*! - * @brief Helper API to check if a node is a valid layer type - * @ingroup layers_common - * @param type in type of layer - * @return true if the layer is one of the ones listed in the enum, - * false otherwise - */ -AI_INTERNAL_API -ai_bool ai_layer_type_is_valid(const ai_layer_type type); - -AI_API_DECLARE_END - -#endif /* __LAYERS_COMMON_H_ */ diff --git a/src/stm32cubeai/AI/Inc/layers_conv2d.h b/src/stm32cubeai/AI/Inc/layers_conv2d.h deleted file mode 100755 index 4b75a7c5f..000000000 --- a/src/stm32cubeai/AI/Inc/layers_conv2d.h +++ /dev/null @@ -1,196 +0,0 @@ -/** - ****************************************************************************** - * @file layers_conv2d.h - * @author AST Embedded Analytics Research Platform - * @date 18-Apr-2018 - * @brief header file of AI platform conv2d layers datatypes - ****************************************************************************** - * @attention - * - *

© Copyright (c) 2018 STMicroelectronics. - * All rights reserved.

- * - * This software component is licensed by ST under Ultimate Liberty license - * SLA0044, the "License"; You may not use this file except in compliance with - * the License. You may obtain a copy of the License at: - * www.st.com/SLA0044 - * - ****************************************************************************** - */ -#ifndef __LAYERS_CONV2D_H_ -#define __LAYERS_CONV2D_H_ -#pragma once - -#include "layers_nl.h" -#include "layers_pool.h" - -#define AI_LAYER_CONV2D_FIELDS_DECLARE \ - AI_LAYER_COMMON_FIELDS_DECLARE \ - ai_u32 groups; /*!< groups for separable convolution */ \ - AI_CONST ai_array* nl_params; /*!< array pointer to non linear parameters */ \ - func_nl nl_func; /*!< function pointer to non linear transform */ \ - ai_shape_2d filter_stride; /*!< filter stride, how much the filter moves */ \ - ai_shape_2d dilation; /*!< dilation value along axis of the filter */ \ - ai_shape filter_pad; /*!< filter pad 4d */ - -/*! - * @defgroup layers_conv2d Convolutive Layers Definitions - * @brief definition - * - */ - -AI_API_DECLARE_BEGIN - -/*! - * @struct ai_layer_dense - * @ingroup layers_conv2d - * @brief Dense (fully connected) layer - */ -typedef ai_layer ai_layer_dense; - -/*! - * @struct ai_layer_gemm - * @ingroup layers_conv2d - * @brief layer for General Matrix Multiplication - * - * Layer for General Matrix Multiplication (GEMM): - * \f{equation}{ Y = \alpha A \cdot B + \beta C \f} - * \f$\alpha\f$ and \f$\beta\f$ are paramaters, A and B are matrices, - * C is a matrix or an array. Size checks for A, B, C, and Y are performed and - * broadcast is applied on C if necessary. - * This is a sequential layer (see @ref ai_layer). - */ -typedef AI_ALIGNED_TYPE(struct, 4) ai_layer_gemm_ { - AI_LAYER_COMMON_FIELDS_DECLARE - ai_float alpha; /*!< alpha coefficient */ - ai_float beta; /*!< beta coefficient */ - ai_u8 tA; /*!< transpose A flag */ - ai_u8 tB; /*!< transpose B flag */ -} ai_layer_gemm; - -/*! - * @struct ai_layer_conv2d - * @ingroup layers_conv2d - * @brief 2D convolutional layer with strides and pads - */ -typedef AI_ALIGNED_TYPE(struct, 4) ai_layer_conv2d_ { - AI_LAYER_CONV2D_FIELDS_DECLARE -} ai_layer_conv2d; - -/*! - * @struct ai_layer_conv2d_nl_pool - * @ingroup layers_conv2d - * @brief 2D convolutional layer + nl + pooling with strides and pads - */ -typedef AI_ALIGNED_TYPE(struct, 4) ai_layer_conv2d_nl_pool_ { - AI_LAYER_CONV2D_FIELDS_DECLARE - - ai_shape_2d pool_size; /*!< pooling size */ - ai_shape_2d pool_stride; /*!< pooling stride */ - ai_shape pool_pad; /*!< pooling pad */ - - func_pool pool_func; /*!< function pointer to pooling transform */ -} ai_layer_conv2d_nl_pool; - - -AI_INTERNAL_API -void ai_dict8_dot_array_f32(ai_handle out, ai_ptr_const data0, ai_ptr_const lut, - const ai_float* data1, const ai_size data_size); - -AI_INTERNAL_API -void ai_dict4_dot_array_f32(ai_handle out, ai_ptr_const data0, ai_ptr_const lut, - const ai_float* data1, const ai_size data_size);/******************************************************************************/ -/* Forward Functions Section */ -/******************************************************************************/ - -/*! - * @brief Computes the activations of a 2D convolutional layer. - * @ingroup layers_conv2d - * @param layer the convolutional (conv) layer - */ -AI_INTERNAL_API -void forward_conv2d(ai_layer* layer); - -/*! - * @brief Computes the activations of a @ref ai_layer_conv2d_nl_pool layer - * The @ref ai_layer_conv2d_nl_pool is a fused conv2D + optional nonlinear - * layer + optional pooling / nonlinearity (average, max, softmax) - * @ingroup layers_conv2d - * @param layer see @ai_layer_conv2d_nl_pool - */ -AI_INTERNAL_API -void forward_conv2d_nl_pool(ai_layer* layer); - -/*! - * @brief Computes the activations of a GEMM layer. - * @ingroup layers - * @param layer the layer including output and input tensors - */ -AI_INTERNAL_API -void forward_gemm(ai_layer* layer); - -/*! - * @brief Computes matmul layer, intended as numpy.matmul(A,B). - * @ingroup layers - * @param layer the layer including output and input tensors - */ -AI_INTERNAL_API -void forward_matmul(ai_layer* layer); - -/*! - * @brief Computes the activations of a dense (fully connected) layer. - * @ingroup layers_conv2d - * @param layer the dense layer - */ -AI_INTERNAL_API -void forward_dense(ai_layer* layer); - - -/*! - * @brief Computes the activations of a fixed point 2D convolutional layer. - * @ingroup layers_conv2d - * @param layer the convolutional (conv) layer - */ -AI_INTERNAL_API -void forward_conv2d_fixed(ai_layer *pLayer); - -/*! - * @brief Computes the activations of a fixed point @ref ai_layer_conv2d_nl_pool - * layer. - * The @ref ai_layer_conv2d_nl_pool is a fused conv2D + optional nonlinear - * layer + optional pooling / nonlinearity (average, max) - * @ingroup layers_conv2d - * @param layer see @ai_layer_conv2d_nl_pool - */ -AI_INTERNAL_API -void forward_conv2d_nl_pool_fixed(ai_layer *pLayer); - -/*! - * @brief Computes the activations of a integer quantized 2D convolutional layer. - * @ingroup layers_conv2d - * @param layer the convolutional (conv) layer - */ -AI_INTERNAL_API -void forward_conv2d_integer(ai_layer *pLayer); - -/*! - * @brief Computes the activations of a integer @ref ai_layer_conv2d_nl_pool layer. - * The @ref ai_layer_conv2d_nl_pool is a fused conv2D + optional nonlinear - * layer + optional pooling / nonlinearity (average, max) - * @ingroup layers_conv2d - * @param layer see @ai_layer_conv2d_nl_pool - */ -AI_INTERNAL_API -void forward_conv2d_nl_pool_integer(ai_layer *pLayer); - -/*! - * @brief Computes the activations of a integer dense (fully connected) layer. - * @ingroup layers_dense - * @param layer the dense layer - */ -AI_INTERNAL_API -void forward_dense_integer(ai_layer *pLayer); - -AI_API_DECLARE_END - -#endif /*__LAYERS_CONV2D_H_*/ diff --git a/src/stm32cubeai/AI/Inc/layers_dense.h b/src/stm32cubeai/AI/Inc/layers_dense.h deleted file mode 100755 index a67c3f2e9..000000000 --- a/src/stm32cubeai/AI/Inc/layers_dense.h +++ /dev/null @@ -1,65 +0,0 @@ -/** - ****************************************************************************** - * @file layers_dense.h - * @author AST Embedded Analytics Research Platform - * @date 18-Apr-2018 - * @brief header file of AI platform dense layers datatypes - ****************************************************************************** - * @attention - * - *

© COPYRIGHT(c) 2018 STMicroelectronics

- * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of STMicroelectronics nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - ****************************************************************************** - */ - -#ifndef __LAYERS_DENSE_H_ -#define __LAYERS_DENSE_H_ -#pragma once - - -#include "layers_common.h" - - -/*! - * @defgroup layers Normalization Layers Definitions - * @brief definition - * - */ - -AI_API_DECLARE_BEGIN - -/*! - * @brief Computes the activations of a fixed point dense (fully connected) layer. - * @ingroup layers_dense - * @param layer the dense layer - */ -AI_INTERNAL_API -void forward_dense_fixed(ai_layer *pLayer); - -AI_API_DECLARE_END - -#endif /*__LAYERS_DENSE_H_*/ - diff --git a/src/stm32cubeai/AI/Inc/layers_generic.h b/src/stm32cubeai/AI/Inc/layers_generic.h deleted file mode 100755 index 76cce1c58..000000000 --- a/src/stm32cubeai/AI/Inc/layers_generic.h +++ /dev/null @@ -1,371 +0,0 @@ - -/** - ****************************************************************************** - * @file layers_generic.h - * @author AST Embedded Analytics Research Platform - * @date 18-Apr-2018 - * @brief header file of AI platform generic layers datatypes - ****************************************************************************** - * @attention - * - *

© Copyright (c) 2018 STMicroelectronics. - * All rights reserved.

- * - * This software component is licensed by ST under Ultimate Liberty license - * SLA0044, the "License"; You may not use this file except in compliance with - * the License. You may obtain a copy of the License at: - * www.st.com/SLA0044 - * - ****************************************************************************** - */ -#ifndef __LAYERS_GENERIC_H_ -#define __LAYERS_GENERIC_H_ -#pragma once - -#include "layers_common.h" - -/*! - * @defgroup layers_generic Generic Layers Definitions - * @brief definition - * - */ - -AI_API_DECLARE_BEGIN - -/*! - * @struct ai_layer_time_delay - * @ingroup layers_generic - * @brief TimeDelay layer with sparse kernel - */ -typedef AI_ALIGNED_TYPE(struct, 4) ai_layer_time_delay_ { - AI_LAYER_COMMON_FIELDS_DECLARE - AI_CONST ai_array* mask; /*!< sparse filter mask */ -} ai_layer_time_delay; - -/*! - * @struct ai_layer_split - * @ingroup layers_generic - * @brief Split layer definition - * - * This layer defines the params of a splitting layer. It is intended to be used - * by his associated forward function @ref forward_split - */ -typedef AI_ALIGNED_TYPE(struct, 4) ai_layer_split_ { - AI_LAYER_COMMON_FIELDS_DECLARE - ai_u16 out_layers_count; /*!< number of output layers to split*/ - ai_u16 out_layer_curr; /*!< current layer to split */ - ai_layer** out_layers; /*!< output layers list */ - ai_tensor** out_tensors; /*!< output tensors list */ - ai_tensor* in_tensor; /*!< input tensor */ - func_copy_tensor copy_to_out_tensor; /*!< pointer to copy tensor func - (NULL = no copy) */ -} ai_layer_split; - -/*! - * @struct ai_layer_topK - * @ingroup layers_generic - * @brief topK layer definition - */ -typedef AI_ALIGNED_TYPE(struct, 4) ai_layer_topK_{ - AI_LAYER_COMMON_FIELDS_DECLARE - ai_i16 axis; - ai_i32 k; -} ai_layer_topK; - - -/*! - * @struct ai_layer_slice - * @ingroup layers_generic - * @brief Slice layer definition - * - * This layer defines the params of a slicing layer. It is intended to be used - * by his associated forward function @ref forward_slice - */ -typedef AI_ALIGNED_TYPE(struct, 4) ai_layer_slice_ { - AI_LAYER_COMMON_FIELDS_DECLARE - AI_CONST ai_array* axes; /*!< Axes that 'starts' and 'ends' apply to. It's optional*/ - AI_CONST ai_array* starts; /*!< Starting indices of corrisponding axis in axes*/ - AI_CONST ai_array* ends; /*!< Ending indices (exclusive) of corrisponding axis in axes*/ -} ai_layer_slice; - - -/*! - * @struct ai_layer_tile - * @ingroup layers generic - * @brief Tile layer definition - * - * This layer defines the param of an tile layer. It constructs a tensor by tiling a - * given tensor. It is intended to be used by its associated forward function - * @ref forward_upsample - */ -typedef AI_ALIGNED_TYPE(struct, 4) ai_layer_tile_{ - AI_LAYER_COMMON_FIELDS_DECLARE - AI_CONST ai_array* repeats; /*!< numbers of repeated copies along each dimension */ -} ai_layer_tile; - -/*! - * @struct ai_layer_upsample - * @ingroup layers generic - * @brief Upsample layer definition - * - * This layer defines the param of an upsampling layer. It overloads its params - * to allow zeros upsampling, helpful traspose convolutions, for instance. - * It is intended to be used by its associated forward function @ref forward_upsample - */ -typedef AI_ALIGNED_TYPE(struct, 4) ai_layer_upsample_{ - AI_LAYER_COMMON_FIELDS_DECLARE - ai_upsample_mode mode; /*!< upsample mode */ - AI_CONST ai_array* scales; /*!< scale array along each dimension */ -} ai_layer_upsample; - -/*! - * @struct ai_layer_instanceNormalization - * @ingroup layers generic - * @brief instance normalization layer definition - * - * This layer defines the params of an instance normalization layer. - * It is intended to be used by its associated forward function @ref forward_instanceNormalization - */ -typedef AI_ALIGNED_TYPE(struct, 4) ai_layer_instanceNormaization_{ - AI_LAYER_COMMON_FIELDS_DECLARE - ai_float eps; /*!< epsilon value, to avoid by zero division */ - AI_CONST ai_array* scale; /*!< scale array */ - AI_CONST ai_array* bias; /*!< bias array */ -} ai_layer_instanceNormalization; - -/*! - * @struct ai_layer_mode - * @ingroup layers generic - * @brief Pad layer definition - * - * This layer defines the param of an pad layer. It pad a tensor. - * It is intended to be used by its associated forward function @ref forward_pad - */ -typedef AI_ALIGNED_TYPE(struct, 4) ai_layer_pad_{ - AI_LAYER_COMMON_FIELDS_DECLARE - ai_pad_mode mode; /*!< pad mode */ - ai_shape pads; /*!< Number of padding to add or remove at the beginning and end of each axis */ - ai_float value; /*!< Indicates the value to be filled */ -} ai_layer_pad; -/*! - * @struct ai_layer_add - * @ingroup layers_generic - * @brief Add layer definition - * - * This layer defines the params of an add layer. - */ -typedef AI_ALIGNED_TYPE(struct, 4) ai_layer_add_ { - AI_LAYER_COMMON_FIELDS_DECLARE - ai_u16 in_layers_count; /*!< number of input layers to concat */ - ai_u16 in_layer_curr; /*!< current layer to concat */ - ai_tensor** in_tensors; /*!< input tensors list (if NULL==no copy) */ - ai_tensor* out_tensor; /*!< output tensor (if NULL==no copy) */ - func_copy_tensor copy_to_out_tensor; /*!< pointer to copy tensor func - (NULL = no copy) */ - ai_layer* split_layer; /*!< pointer to associated split layer */ - ai_layer* next_layer; /*!< pointer to next layer to process */ -} ai_layer_add; - -/*! - * @struct ai_layer_transpose - * @ingroup layers_generic - * @brief Transpose layer datastruct declaration. This defines the params of a - * transpose layer. It is intended to be used by his associated forward function - * @ref forward_transpose - */ -typedef AI_ALIGNED_TYPE(struct, 4) ai_layer_transpose_ { - AI_LAYER_COMMON_FIELDS_DECLARE - ai_shape out_mapping; /*!< transpose output mapping order. I.e. tt is a - permutation of the input tensor shape */ -} ai_layer_transpose; - - -#define AI_TIME_DISTRIBUTED_AXIS (AI_SHAPE_HEIGHT) - -/*! - * @struct ai_layer_time_distributed - * @ingroup layers_generic - * @brief Time distributed layer datastruct declaration. This defines the params - * of a time distributed layer. It is intended to be used by his associated - * forward function @ref forward_time_distributed - */ -typedef AI_ALIGNED_TYPE(struct, 4) ai_layer_time_distributed_ { - AI_LAYER_COMMON_FIELDS_DECLARE - ai_layer* inner_layer; /*!< inner layer to process */ -} ai_layer_time_distributed; - -/*! - * @struct ai_layer_concat - * @ingroup layers_generic - * @brief Concatenation layer - * - * Concat Layer. - * It is a sequential layer. see @ref ai_layer_sequential - */ -typedef AI_ALIGNED_TYPE(struct, 4) ai_layer_concat_ { - AI_LAYER_COMMON_FIELDS_DECLARE - ai_shape_dimension axis; /*!< which axis to concatenate on */ -} ai_layer_concat; - -typedef ai_float (*func_binary)(const ai_float a, const ai_float b); - -/*! - * @struct ai_layer_eltwise - * @ingroup layers_generic - * @brief General element-wise transformation layer - * - * Elementwise Layer. - * It is a sequential layer. see @ref ai_layer_sequential - */ -typedef AI_ALIGNED_TYPE(struct, 4) ai_layer_eltwise_ { - AI_LAYER_COMMON_FIELDS_DECLARE - func_binary operation; /*!< operation to apply elementwise */ -} ai_layer_eltwise; - -/*! - * @struct ai_layer_reduce - * @ingroup layers_generic - * @brief General dimension reduction layer - * - * reduction Layer. - * It is a sequential layer. see @ref ai_layer_sequential - */ -typedef AI_ALIGNED_TYPE(struct, 4) ai_layer_reduce_ { - AI_LAYER_COMMON_FIELDS_DECLARE - ai_float neutral_value; /*!< Initialization value for operation */ - func_binary operation; /*!< operation to apply elementwise */ -} ai_layer_reduce; - - -/******************************************************************************/ -/* Forward Functions Section */ -/******************************************************************************/ - -/*! - * @brief Computes the activations of a TimeDelay layer. - * @ingroup layers_generic - * @param layer the time delay layer - */ -AI_INTERNAL_API -void forward_time_delay(ai_layer* layer); - -/*! - * @brief Split network computation in N parallel branches. - * @ingroup layers_generic - * @param layer the split layer - */ -AI_INTERNAL_API -void forward_split(ai_layer* layer); - -/*! - * @brief Add network computation from N parallel branches. - * @ingroup layers_generic - * @param layer the add layer - */ -AI_INTERNAL_API -void forward_add(ai_layer* layer); - -/*! - * @brief Transpose a tensor along a pivot and save transposed values into an output - * tensor - * @ingroup layers_generic - * @param layer the transpose layer - */ -AI_INTERNAL_API -void forward_transpose(ai_layer* layer); - -/*! - * @brief TimeDistrubuted forward layer function. This forward function - * implements the timedistributed layer. - * @ingroup layers_generic - * @param layer the time distributed layer - */ -AI_INTERNAL_API -void forward_time_distributed(ai_layer* layer); - - -/*! - * @brief Concatenates a list of tensors into a single tensor. - * @ingroup layers_generic - * @param layer the concatenation layer - */ -AI_INTERNAL_API -void forward_concat(ai_layer* layer); - -/*! - * @brief Slice an input tensors - * @ingroup layers_generic - * @param layer the sliced layer - */ -AI_INTERNAL_API -void forward_slice(ai_layer* layer); - -/*! - * @brief Tile an input tensors - * @ingroup layers_generic - * @param layer the tiled layer - */ -AI_INTERNAL_API -void forward_tile(ai_layer* layer); - -/*! - * @brief TopK an input tensors - * @ingroup layers_generic - * @param layer the Topked layer - */ -AI_INTERNAL_API -void forward_topK(ai_layer* layer); - -/*! - * @brief Pad an input tensors - * @ingroup layers_generic - * @param layer the pad layer - */ -AI_INTERNAL_API -void forward_pad(ai_layer* layer); - -/*! - * @brief Upsample an input tensors - * @ingroup layers_generic - * @param layer the upsampled layer - */ -AI_INTERNAL_API -void forward_upsample(ai_layer* layer); - -/*! - * @brief Instance Normalization on an input tensors - * @ingroup layers_generic - * @param layer the instance normalization layer - */ -AI_INTERNAL_API -void forward_instanceNormalization(ai_layer* layer); - -/*! - * @brief Apply an elementwise transformation to the input tensors - * @ingroup layers_generic - * @param layer the elementwise layer - */ -AI_INTERNAL_API -void forward_eltwise(ai_layer* layer); - -/*! - * @brief Apply a reduce transformation to the input tensors - * @ingroup layers_generic - * @param layer the reduce layer - */ -AI_INTERNAL_API -void forward_reduce(ai_layer* layer); - - -/*! - * @brief Apply an elementwise addition to the input tensors - * @ingroup layers_generic - * @param layer the elementwise layer - */ -AI_INTERNAL_API -void forward_add_integer(ai_layer* layer); - - -AI_API_DECLARE_END - -#endif /*__LAYERS_GENERIC_H_*/ diff --git a/src/stm32cubeai/AI/Inc/layers_list.h b/src/stm32cubeai/AI/Inc/layers_list.h deleted file mode 100755 index 3eece46d3..000000000 --- a/src/stm32cubeai/AI/Inc/layers_list.h +++ /dev/null @@ -1,92 +0,0 @@ -/** - ****************************************************************************** - * @file layers_list.h - * @author AST Embedded Analytics Research Platform - * @date 20-Jul-2018 - * @brief header file of AI platform layers datatypes - ****************************************************************************** - * @attention - * - *

© Copyright (c) 2018 STMicroelectronics. - * All rights reserved.

- * - * This software component is licensed by ST under Ultimate Liberty license - * SLA0044, the "License"; You may not use this file except in compliance with - * the License. You may obtain a copy of the License at: - * www.st.com/SLA0044 - * - ****************************************************************************** - */ - - -/* No sentry. This is deliberate!! */ -/* Template: LAYER_ENTRY(type_, id_, struct_, forward_func_) - * Where: - * - type_ is the (enum) type name of the layer. to have the complete enum - * value you should use the macro @ref AI_LAYER_TYPE_ENTRY(type_) that adds - * the specific prefix and postfix tokens to the type_ - * - id_ is the numeric id of the layer - * - struct_ is the name of the datastruct of the layer - * - forward_func_ is the forward function name of the routine implementing - * actual layer processing - */ - -/*!< Elementwise addition layer */ -LAYER_ENTRY(ADD, 10001, ai_layer_add, forward_add) - /*!< Batch normalization layer */ -LAYER_ENTRY(BN, 10002, ai_layer_bn, forward_bn) -/*!< 2D Convolutional layer */ -LAYER_ENTRY(CONV2D, 10004, ai_layer_conv2d, forward_conv2d) -/*!< Dense layer */ -LAYER_ENTRY(DENSE, 10005, ai_layer_dense, forward_dense) -/*!< Gated Recurrent Unit layer */ -LAYER_ENTRY(GRU, 10006, ai_layer_gru, forward_gru) -/*!< Local Response Normalization layer */ -LAYER_ENTRY(LRN, 10007, ai_layer_lrn, forward_lrn) -/*!< Long Short Time Memory layer */ -LAYER_ENTRY(LSTM, 10008, ai_layer_lstm, forward_lstm) -/*!< Nonlinearity layer */ -LAYER_ENTRY(NL, 10009, ai_layer_nl, NULL) -/*!< Normalization layer */ -LAYER_ENTRY(NORM, 10010, ai_layer_norm, forward_norm) -/*!< Merged Conv2d / Pool layer */ -LAYER_ENTRY(OPTIMIZED_CONV2D, 10011, ai_layer_conv2d_nl_pool, forward_conv2d_nl_pool) -/*!< Transpose Tensor layer */ -LAYER_ENTRY(TRANSPOSE, 10012, ai_layer_transpose, forward_transpose) -/*!< Pooling layer */ -LAYER_ENTRY(POOL, 10013, ai_layer_pool, forward_pool) -/*!< Softmax layer */ -LAYER_ENTRY(SM, 10014, ai_layer_nl, forward_sm) -/*!< Split layer */ -LAYER_ENTRY(SPLIT, 10015, ai_layer_split, forward_split) -/*!< TimeDelay layer */ -LAYER_ENTRY(TIME_DELAY, 10016, ai_layer_time_delay, forward_time_delay) -/*!< TimeDistributed layer */ -LAYER_ENTRY(TIME_DISTRIBUTED, 10017, ai_layer_time_distributed, forward_time_distributed) -/*!< Concat Tensor layer */ -LAYER_ENTRY(CONCAT, 10019, ai_layer_concat, forward_concat) -/*!< GEMM layer */ -LAYER_ENTRY(GEMM, 10020, ai_layer_gemm, forward_gemm) -/*!< Upsample layer */ -LAYER_ENTRY(UPSAMPLE, 10021, ai_layer_upsample, forward_upsample) -/*!< Container layer for eltwise operations */ -LAYER_ENTRY(ELTWISE, 10022, ai_layer_eltwise, forward_eltwise) -/*!< Generic layer */ -LAYER_ENTRY(GENERIC, 10023, ai_layer, NULL) -/*!< InstanceNormalization layer */ -LAYER_ENTRY(INSTANCENORMALIZATION, 10024, ai_layer_instanceNormalization, forward_instanceNormalization) -/*!< Pad layer */ -LAYER_ENTRY(PAD, 10025, ai_layer_pad, forward_pad) -/*!< Slice layer */ -LAYER_ENTRY(SLICE, 10026, ai_layer_slice, forward_slice) -/*!< Tile layer */ -LAYER_ENTRY(TILE, 10027, ai_layer_tile, forward_tile) -/*!< Container layer for reduce operations */ -LAYER_ENTRY(REDUCE, 10028, ai_layer_reduce, forward_reduce) -#ifdef USE_OPERATORS -/*!< Container layer for operators */ -LAYER_ENTRY(CONTAINER, 10003, ai_layer_container, forward_container) -/*!< Container layer for operators */ -LAYER_ENTRY(LAMBDA, 10018, ai_layer_lambda, forward_lambda) -#endif -#undef LAYER_ENTRY diff --git a/src/stm32cubeai/AI/Inc/layers_nl.h b/src/stm32cubeai/AI/Inc/layers_nl.h deleted file mode 100755 index f63442404..000000000 --- a/src/stm32cubeai/AI/Inc/layers_nl.h +++ /dev/null @@ -1,925 +0,0 @@ -/** - ****************************************************************************** - * @file layers_nl.h - * @author AST Embedded Analytics Research Platform - * @date 18-Apr-2018 - * @brief header file of AI platform nonlinearity layers datatypes - ****************************************************************************** - * @attention - * - *

© Copyright (c) 2018 STMicroelectronics. - * All rights reserved.

- * - * This software component is licensed by ST under Ultimate Liberty license - * SLA0044, the "License"; You may not use this file except in compliance with - * the License. You may obtain a copy of the License at: - * www.st.com/SLA0044 - * - ****************************************************************************** - */ -#ifndef __LAYERS_NL_H_ -#define __LAYERS_NL_H_ -#pragma once - -#include "layers_common.h" - -/*! - * @defgroup layers_nl Normalization Layers Definitions - * @brief definition - * - */ - -AI_API_DECLARE_BEGIN - -/*! - * @struct ai_layer_nl - * @ingroup layers_nl - * @brief Generic Nonlinearity layer - * - * The type of nonlinearity is handled by the specific forward function. - * It is a sequential layer. see @ref ai_layer - */ -typedef AI_ALIGNED_TYPE(struct, 4) ai_layer_nl_ { - AI_LAYER_COMMON_FIELDS_DECLARE - AI_CONST ai_array* nl_params; /*!< associated parameters array */ -} ai_layer_nl; - -/*! - * @typedef (*func_nl) - * @ingroup layers_nl - * @brief Fuction pointer for generic non linear transform - * this function pointer abstracts a generic non linear layer. - * see @ref nl_func_tanh_array_f32 and similar as examples. - */ -typedef void (*func_nl)(ai_array *out, const ai_array *in, - const ai_size size, const ai_handle params); - -/*! - * @brief Softmax pooling computed on a single float channel - * @ingroup layers_nl - * @param out opaque handler to float output channel - * @param in opaque handler to float input channel - * @param channel_size number of elements of the input channel - * @param params opaque handler to optional nl parameters - */ -AI_INTERNAL_API -void nl_func_sm_channel_f32(ai_array *out, const ai_array *in, - const ai_size channel_size, const ai_handle params); - -/*! - * @brief Softmax normalization computed on an array of float channels - * @ingroup layers_nl - * @param out opaque handler to float output channel array - * @param in opaque handler to float input channel array - * @param in_size total size (number of elements) to process on the input - * @param channel_size number of elements of the input channel - * @param in_channel_step number of elements to move to next input element - * @param out_channel_step number of elements to move to next output element - */ -AI_INTERNAL_API -void nl_func_sm_array_f32(ai_array *out, ai_array *in, - const ai_size in_size, - const ai_size channel_size, - const ai_size in_channel_step, - const ai_size out_channel_step); - -/*! - * @brief Computes the tanh function on a float data array - * @ingroup layers_nl - * @param in opaque handler to float, size should be 1 - * @param out opaque handler to float output elem - * @param size number of elements in the input buffer - * @param params opaque handler to optional nl parameters - */ -AI_INTERNAL_API -void nl_func_tanh_array_f32(ai_array *out, const ai_array *in, - const ai_size size, const ai_handle params); - -/*! - * @brief Computes the tanh function on a fixed point data array - * @ingroup layers_nl - * @param in opaque handler to input elements to process - * @param out opaque handler to output elements - * @param size total size (number of elements) to process on the input - * @param params opaque handler to optional nl parameters - */ -AI_INTERNAL_API -void nl_func_tanh_array_fixed(ai_array *out, const ai_array *in, - const ai_size size, const ai_handle params); - - -/*! - * @brief Computes the sigmoid function on a float data array - * @ingroup layers_nl - * @param in opaque handler to float, size should be 1 - * @param out opaque handler to float output elem - * @param size number of elements in the input buffer - * @param params opaque handler to optional nl parameters - */ -AI_INTERNAL_API -void nl_func_sigmoid_array_f32(ai_array *out, const ai_array *in, - const ai_size size, const ai_handle params); - -/*! - * @brief Computes the sigmoid function on a fixed point data array - * @ingroup layers_nl - * @param in opaque handler to input elements to process - * @param out opaque handler to output elements - * @param size total size (number of elements) to process on the input - * @param params opaque handler to optional nl parameters - */ -AI_INTERNAL_API -void nl_func_sigmoid_array_fixed(ai_array *out, const ai_array *in, - const ai_size size, const ai_handle params); - - -/*! - * @brief Computes the hard sigmoid function on a float data array - * @ingroup layers_nl - * @param in opaque handler to float, size should be 1 - * @param out opaque handler to float output elem - * @param size number of elements in the input buffer - * @param params opaque handler to optional nl parameters - */ -AI_INTERNAL_API -void nl_func_hard_sigmoid_array_f32(ai_array *out, const ai_array *in, - const ai_size size, const ai_handle params); - -/*! - * @brief Computes the absolute value function on a float data array - * @ingroup layers_nl - * @param in opaque handler to float, size should be 1 - * @param out opaque handler to float output elem - * @param size number of elements in the input buffer - * @param params opaque handler to optional nl parameters - */ -AI_INTERNAL_API -void nl_func_abs_array_f32(ai_array *out, const ai_array *in, - const ai_size size, const ai_handle params); - -/*! - * @brief Computes the cosine function on a float data array - * @ingroup layers_nl - * @param in opaque handler to float, size should be 1 - * @param out opaque handler to float output elem - * @param size number of elements in the input buffer - * @param params opaque handler to optional nl parameters - */ -AI_INTERNAL_API -void nl_func_cos_array_f32(ai_array *out, const ai_array *in, - const ai_size size, const ai_handle params); - -/*! - * @brief Computes the inverse cosine function on a float data array - * @ingroup layers_nl - * @param in opaque handler to float, size should be 1 - * @param out opaque handler to float output elem - * @param size number of elements in the input buffer - * @param params opaque handler to optional nl parameters - */ -AI_INTERNAL_API -void nl_func_acos_array_f32(ai_array *out, const ai_array *in, - const ai_size size, const ai_handle params); - -/*! - * @brief Computes the hyperbolic cosine function on a float data array - * @ingroup layers_nl - * @param in opaque handler to float, size should be 1 - * @param out opaque handler to float output elem - * @param size number of elements in the input buffer - * @param params opaque handler to optional nl parameters - */ -AI_INTERNAL_API -void nl_func_cosh_array_f32(ai_array *out, const ai_array *in, - const ai_size size, const ai_handle params); - -/*! - * @brief Computes the inverse hyperbolic cosine function on a float data array - * @ingroup layers_nl - * @param in opaque handler to float, size should be 1 - * @param out opaque handler to float output elem - * @param size number of elements in the input buffer - * @param params opaque handler to optional nl parameters - */ -AI_INTERNAL_API -void nl_func_acosh_array_f32(ai_array *out, const ai_array *in, - const ai_size size, const ai_handle params); - -/*! - * @brief Computes the sine function on a float data array - * @ingroup layers_nl - * @param in opaque handler to float, size should be 1 - * @param out opaque handler to float output elem - * @param size number of elements in the input buffer - * @param params opaque handler to optional nl parameters - */ -AI_INTERNAL_API -void nl_func_sin_array_f32(ai_array *out, const ai_array *in, - const ai_size size, const ai_handle params); - -/*! - * @brief Computes the inverse sine function on a float data array - * @ingroup layers_nl - * @param in opaque handler to float, size should be 1 - * @param out opaque handler to float output elem - * @param size number of elements in the input buffer - * @param params opaque handler to optional nl parameters - */ -AI_INTERNAL_API -void nl_func_asin_array_f32(ai_array *out, const ai_array *in, - const ai_size size, const ai_handle params); - -/*! - * @brief Computes the hyperbolic sine function on a float data array - * @ingroup layers_nl - * @param in opaque handler to float, size should be 1 - * @param out opaque handler to float output elem - * @param size number of elements in the input buffer - * @param params opaque handler to optional nl parameters - */ -AI_INTERNAL_API -void nl_func_sinh_array_f32(ai_array *out, const ai_array *in, - const ai_size size, const ai_handle params); - -/*! - * @brief Computes the inverse hyperbolic sine function on a float data array - * @ingroup layers_nl - * @param in opaque handler to float, size should be 1 - * @param out opaque handler to float output elem - * @param size number of elements in the input buffer - * @param params opaque handler to optional nl parameters - */ -AI_INTERNAL_API -void nl_func_asinh_array_f32(ai_array *out, const ai_array *in, - const ai_size size, const ai_handle params); - -/*! - * @brief Computes the tangent function on a float data array - * @ingroup layers_nl - * @param in opaque handler to float, size should be 1 - * @param out opaque handler to float output elem - * @param size number of elements in the input buffer - * @param params opaque handler to optional nl parameters - */ -AI_INTERNAL_API -void nl_func_tan_array_f32(ai_array *out, const ai_array *in, - const ai_size size, const ai_handle params); - -/*! - * @brief Computes the inverse tangent function on a float data array - * @ingroup layers_nl - * @param in opaque handler to float, size should be 1 - * @param out opaque handler to float output elem - * @param size number of elements in the input buffer - * @param params opaque handler to optional nl parameters - */ -AI_INTERNAL_API -void nl_func_atan_array_f32(ai_array *out, const ai_array *in, - const ai_size size, const ai_handle params); - -/*! - * @brief Computes the inverse hyperbolic tangent function on a float data array - * @ingroup layers_nl - * @param in opaque handler to float, size should be 1 - * @param out opaque handler to float output elem - * @param size number of elements in the input buffer - * @param params opaque handler to optional nl parameters - */ -AI_INTERNAL_API -void nl_func_atanh_array_f32(ai_array *out, const ai_array *in, - const ai_size size, const ai_handle params); - -/*! - * @brief Computes the error function on a float data array - * @ingroup layers_nl - * @param in opaque handler to float, size should be 1 - * @param out opaque handler to float output elem - * @param size number of elements in the input buffer - * @param params opaque handler to optional nl parameters - */ -AI_INTERNAL_API -void nl_func_erf_array_f32(ai_array *out, const ai_array *in, - const ai_size size, const ai_handle params); - -/*! - * @brief Computes the natural logarithm function on a float data array - * @ingroup layers_nl - * @param in opaque handler to float, size should be 1 - * @param out opaque handler to float output elem - * @param size number of elements in the input buffer - * @param params opaque handler to optional nl parameters - */ -AI_INTERNAL_API -void nl_func_log_array_f32(ai_array *out, const ai_array *in, - const ai_size size, const ai_handle params); - -/*! - * @brief Computes the reciprocal square root function on a float data array - * @ingroup layers_nl - * @param in opaque handler to float, size should be 1 - * @param out opaque handler to float output elem - * @param size number of elements in the input buffer - * @param params opaque handler to optional nl parameters - */ -AI_INTERNAL_API -void nl_func_rsqrt_array_f32(ai_array *out, const ai_array *in, - const ai_size size, const ai_handle params); - -/*! - * @brief Computes the floor function on a float data array - * @ingroup layers_nl - * @param in opaque handler to float, size should be 1 - * @param out opaque handler to float output elem - * @param size number of elements in the input buffer - * @param params opaque handler to optional nl parameters - */ -AI_INTERNAL_API -void nl_func_floor_array_f32(ai_array *out, const ai_array *in, - const ai_size size, const ai_handle params); - -/*! - * @brief Computes the ceil function on a float data array - * @ingroup layers_nl - * @param in opaque handler to float, size should be 1 - * @param out opaque handler to float output elem - * @param size number of elements in the input buffer - * @param params opaque handler to optional nl parameters - */ -AI_INTERNAL_API -void nl_func_ceil_array_f32(ai_array *out, const ai_array *in, - const ai_size size, const ai_handle params); - -/*! - * @brief Computes the rounding function on a float data array - * @ingroup layers_nl - * @param in opaque handler to float, size should be 1 - * @param out opaque handler to float output elem - * @param size number of elements in the input buffer - * @param params opaque handler to optional nl parameters - */ -AI_INTERNAL_API -void nl_func_round_array_f32(ai_array *out, const ai_array *in, - const ai_size size, const ai_handle params); - -/*! - * @brief Computes the exponential function on a float data array - * @ingroup layers_nl - * @param in opaque handler to float, size should be 1 - * @param out opaque handler to float output elem - * @param size number of elements in the input buffer - * @param params opaque handler to optional nl parameters - */ -AI_INTERNAL_API -void nl_func_exp_array_f32(ai_array *out, const ai_array *in, - const ai_size size, const ai_handle params); - -/*! - * @brief Computes the sign negation function on a float data array - * @ingroup layers_nl - * @param in opaque handler to float, size should be 1 - * @param out opaque handler to float output elem - * @param size number of elements in the input buffer - * @param params opaque handler to optional nl parameters - */ -AI_INTERNAL_API -void nl_func_neg_array_f32(ai_array *out, const ai_array *in, - const ai_size size, const ai_handle params); - -/*! - * @brief Computes the reciprocal function on a float data array - * @ingroup layers_nl - * @param in opaque handler to float, size should be 1 - * @param out opaque handler to float output elem - * @param size number of elements in the input buffer - * @param params opaque handler to optional nl parameters - */ -AI_INTERNAL_API -void nl_func_reciprocal_array_f32(ai_array *out, const ai_array *in, - const ai_size size, const ai_handle params); - -/*! - * @brief Computes the square root function on a float data array - * @ingroup layers_nl - * @param in opaque handler to float, size should be 1 - * @param out opaque handler to float output elem - * @param size number of elements in the input buffer - * @param params opaque handler to optional nl parameters - */ -AI_INTERNAL_API -void nl_func_sqrt_array_f32(ai_array *out, const ai_array *in, - const ai_size size, const ai_handle params); - -/*! - * @brief Computes the soft plus function on a float data array - * @ingroup layers_nl - * @param in opaque handler to float, size should be 1 - * @param out opaque handler to float output elem - * @param size number of elements in the input buffer - */ -AI_INTERNAL_API -void nl_func_soft_plus_array_f32(ai_array *out, const ai_array *in, - const ai_size size, const ai_handle params); - -/*! - * @brief Computes the soft sign function on a float data array - * @ingroup layers_nl - * @param in opaque handler to float, size should be 1 - * @param out opaque handler to float output elem - * @param size number of elements in the input buffer - * @param params opaque handler to optional nl parameters - */ -AI_INTERNAL_API -void nl_func_soft_sign_array_f32(ai_array *out, const ai_array *in, - const ai_size size, const ai_handle params); - -/*! - * @brief Computes the sign function on a single float element. - * @ingroup layers_nl - * @param in opaque handler to float, size should be 1 - * @param out opaque handler to float output elem - * @param size number of elements in the input buffer - */ -AI_INTERNAL_API -void nl_func_sign_array_f32(ai_array *out, const ai_array *in, - const ai_size size, const ai_handle params); - -/*! - * @brief Computes the clip function on a float data array - * @ingroup layers_nl - * @param in opaque handler to float, size should be 1 - * @param out opaque handler to float output elem - * @param size number of elements in the input buffer - * @param params opaque handler to optional nl parameters - */ -AI_INTERNAL_API -void nl_func_clip_array_f32(ai_array *out, const ai_array *in, - const ai_size size, const ai_handle params); - -/*! - * @brief Computes the hardmax function on a float data array - * @ingroup layers_nl - * @param in opaque handler to float, size should be 1 - * @param out opaque handler to float output elem - * @param axis direction of the max index to be searched - */ -AI_INTERNAL_API -void nl_func_hardmax_array_f32(ai_array *out, const ai_array *in, - const ai_shape *shape, const ai_handle params); - -/*! - * @brief Computes the generic relu function on a float data array - * @ingroup layers_nl - * @param in opaque handler to float, size should be 1 - * @param out opaque handler to float output elem - * @param size number of elements in the input buffer - * @param params opaque handler to optional nl parameters - */ -AI_INTERNAL_API -void nl_func_relu_generic_array_f32(ai_array *out, const ai_array *in, - const ai_size size, const ai_handle params); - -/*! - * @brief Computes the thresholded relu function on a float data array - * @ingroup layers_nl - * @param in opaque handler to float, size should be 1 - * @param out opaque handler to float output elem - * @param size number of elements in the input buffer - * @param params opaque handler to optional nl parameters - */ -AI_INTERNAL_API -void nl_func_relu_thresholded_array_f32(ai_array *out, const ai_array *in, - const ai_size size, const ai_handle params); - -/*! - * @brief Computes the relu function on a float data array - * @ingroup layers_nl - * @param in opaque handler to float, size should be 1 - * @param out opaque handler to float output elem - * @param size number of elements in the input buffer - * @param params opaque handler to optional nl parameters - */ -AI_INTERNAL_API -void nl_func_relu_array_f32(ai_array *out, const ai_array *in, - const ai_size size, const ai_handle params); - -/*! - * @brief Computes the relu function on a fixed point data array - * @ingroup layers_nl - * @param in opaque handler to input elements to process - * @param out opaque handler to output elements - * @param size total size (number of elements) to process on the input - * @param params opaque handler to optional nl parameters - */ -AI_INTERNAL_API -void nl_func_relu_array_fixed(ai_array *out, const ai_array *in, - const ai_size size, const ai_handle params); - -/*! - * @brief Computes the activation function on an integer-quantized data array - * @ingroup layers_nl - * @param in opaque handler to input elements to process - * @param out opaque handler to output elements - * @param size total size (number of elements) to process on the input - * @param params opaque handler to generated and used LUT - */ -void nl_func_array_integer(ai_array *out, const ai_array *in, - const ai_size size, const ai_handle params); - -/*! - * @brief Computes the elu function on a float data array - * @ingroup layers_nl - * @param in opaque handler to float, size should be 1 - * @param out opaque handler to float output elem - * @param size number of elements in the input buffer - * @param params opaque handler to optional nl parameters - */ -AI_INTERNAL_API -void nl_func_elu_array_f32(ai_array *out, const ai_array *in, - const ai_size size, const ai_handle params); - -/*! - * @brief Computes the max relu function on a fixed point data array - * @ingroup layers_nl - * @param in opaque handler to input elements to process - * @param out opaque handler to output elements - * @param size total size (number of elements) to process on the input - * @param params opaque handler to optional nl parameters - */ -AI_INTERNAL_API -void nl_func_relu_max_array_fixed(ai_array *out, const ai_array *in, - const ai_size size, const ai_handle params); - -/*! - * @brief Computes the selu function on a float data array - * @ingroup layers_nl - * @param in opaque handler to float, size should be 1 - * @param out opaque handler to float output elem - * @param size number of elements in the input buffer - * @param params opaque handler to optional nl parameters - */ -AI_INTERNAL_API -void nl_func_selu_array_f32(ai_array *out, const ai_array *in, - const ai_size size, const ai_handle params); - -/*! - * @brief Computes the prelu function on a float data array - * @ingroup layers_nl - * @param in opaque handler to float, size should be 1 - * @param slope opaque handler to float, size should be 1 - * @param out opaque handler to float output elem - * @param size size of the input data in bytes - * @param params opaque handler to optional nl parameters - */ -AI_INTERNAL_API -void nl_func_prelu_array_f32(ai_array *out, const ai_array *in, - const ai_size size, const ai_handle params); - - -/******************************************************************************/ -/** Forward Functions Section **/ -/******************************************************************************/ - -/*! - * @brief Computes the activations of a ReLU nonlinear layer. - * @ingroup layers_nl - * @param layer the nonlinear (nl) layer - */ -AI_INTERNAL_API -void forward_relu(ai_layer* layer); - -/*! - * @brief Computes the activations of a fixed point ReLU nonlinear layer. - * @ingroup layers_nl - * @param layer the nonlinear (nl) layer - */ -AI_INTERNAL_API -void forward_relu_fixed(ai_layer *pLayer); - -#if 0 -/*! - * @brief Computes the activations of a integer-quantized ReLU nonlinear layer. - * @ingroup layers_nl - * @param layer the nonlinear (nl) layer - */ -AI_INTERNAL_API -void forward_relu_integer(ai_layer *pLayer); -#endif - -/*! - * @brief Computes the activations of a ReLU6 nonlinear layer. - * @ingroup layers_nl - * @param layer the nonlinear (nl) layer - */ -AI_INTERNAL_API -void forward_relu_thresholded(ai_layer* layer); - -/*! - * @brief Computes the activations of a fixed point max ReLU layer. - * @ingroup layers_nl - * @param layer the nonlinear (nl) layer - */ -AI_INTERNAL_API -void forward_relu_max_fixed(ai_layer *pLayer); - - -/*! - * @brief Computes the activations of a ELU nonlinear layer. - * @ingroup layers_nl - * @param layer the nonlinear (nl) layer - */ -AI_INTERNAL_API -void forward_elu(ai_layer* layer); - -/*! - * @brief Computes the activations of a SELU nonlinear layer. - * @ingroup layers_nl - * @param layer the nonlinear (nl) layer - */ -AI_INTERNAL_API -void forward_selu(ai_layer* layer); - -/*! - * @brief Computes the activations of a PRELU nonlinear layer. - * @ingroup layers_nl - * @param layer the nonlinear (nl) layer - */ -AI_INTERNAL_API -void forward_prelu(ai_layer* layer); - -/*! - * @brief Computes the activations of a binary tanh (sign) nonlinear layer. - * @ingroup layers - * @param layer the nonlinear (nl) layer - */ -AI_INTERNAL_API -void forward_sign(ai_layer* layer); - -/*! - * @brief Computes the activations of a clip nonlinear layer. - * @ingroup layers - * @param layer the nonlinear (nl) layer - */ -AI_INTERNAL_API -void forward_clip(ai_layer* layer); - -/*! - * @brief Computes the activations of a sigmoid nonlinear layer. - * @ingroup layers_nl - * @param layer the nonlinear (nl) layer - */ -AI_INTERNAL_API -void forward_sigmoid(ai_layer* layer); - -/*! - * @brief Computes the activations of a fixed point sigmoid nonlinear layer. - * @ingroup layers_nl - * @param layer the nonlinear (nl) layer - */ -AI_INTERNAL_API -void forward_sigmoid_fixed(ai_layer *pLayer); - -/*! - * @brief Computes the activations of a hard sigmoid nonlinear layer. - * @ingroup layers_nl - * @param layer the nonlinear (nl) layer - */ -AI_INTERNAL_API -void forward_hard_sigmoid(ai_layer* layer); - -/*! - * @brief Computes the activations of an exponential nonlinear layer. - * @ingroup layers_nl - * @param layer the nonlinear (nl) layer - */ -AI_INTERNAL_API -void forward_exp(ai_layer* layer); - -/*! - * @brief Computes the activations of an square root nonlinear layer. - * @ingroup layers_nl - * @param layer the nonlinear (nl) layer - */ -AI_INTERNAL_API -void forward_sqrt(ai_layer* layer); - -/*! - * @brief Computes the activations of a soft plus nonlinear layer. - * @ingroup layers_nl - * @param layer the nonlinear (nl) layer - */ -AI_INTERNAL_API -void forward_soft_plus(ai_layer* layer); - -/*! - * @brief Computes the activations of a soft sign nonlinear layer. - * @ingroup layers_nl - * @param layer the nonlinear (nl) layer - */ -AI_INTERNAL_API -void forward_soft_sign(ai_layer* layer); - -/*! - * @brief Computes the activations of a cosine (cos) layer. - * @ingroup layers_nl - * @param layer the nonlinear (nl) layer - */ -AI_INTERNAL_API -void forward_cos(ai_layer* layer); - -/*! - * @brief Computes the activations of a inverse cosine (acos) layer. - * @ingroup layers_nl - * @param layer the nonlinear (nl) layer - */ -AI_INTERNAL_API -void forward_acos(ai_layer* layer); - -/*! - * @brief Computes the activations of a hyperbolic cosine (cosh) layer. - * @ingroup layers_nl - * @param layer the nonlinear (nl) layer - */ -AI_INTERNAL_API -void forward_cosh(ai_layer* layer); - -/*! - * @brief Computes the activations of a inverse hyperbolic cosine (acosh) layer. - * @ingroup layers_nl - * @param layer the nonlinear (nl) layer - */ -AI_INTERNAL_API -void forward_acosh(ai_layer* layer); - -/*! - * @brief Computes the activations of a sine (sin) layer. - * @ingroup layers_nl - * @param layer the nonlinear (nl) layer - */ -AI_INTERNAL_API -void forward_sin(ai_layer* layer); - -/*! - * @brief Computes the activations of a inverse sine (asin) layer. - * @ingroup layers_nl - * @param layer the nonlinear (nl) layer - */ -AI_INTERNAL_API -void forward_asin(ai_layer* layer); - -/*! - * @brief Computes the activations of a hyperbolic sine (sinh) layer. - * @ingroup layers_nl - * @param layer the nonlinear (nl) layer - */ -AI_INTERNAL_API -void forward_sinh(ai_layer* layer); - -/*! - * @brief Computes the activations of a inverse hyperbolic sine (asinh) layer. - * @ingroup layers_nl - * @param layer the nonlinear (nl) layer - */ -AI_INTERNAL_API -void forward_asinh(ai_layer* layer); - -/*! - * @brief Computes the activations of a tangent (tan) layer. - * @ingroup layers_nl - * @param layer the nonlinear (nl) layer - */ -AI_INTERNAL_API -void forward_tan(ai_layer* layer); - -/*! - * @brief Computes the activations of a inverse tangent (atan) layer. - * @ingroup layers_nl - * @param layer the nonlinear (nl) layer - */ -AI_INTERNAL_API -void forward_atan(ai_layer* layer); - -/*! - * @brief Computes the activations of a hyperbolic tangent (tanh) layer. - * @ingroup layers_nl - * @param layer the nonlinear (nl) layer - */ -AI_INTERNAL_API -void forward_tanh(ai_layer* layer); - -/*! - * @brief Computes the activations of a inverse hyperbolic tangent (atanh) layer. - * @ingroup layers_nl - * @param layer the nonlinear (nl) layer - */ -AI_INTERNAL_API -void forward_atanh(ai_layer* layer); - -/*! - * @brief Computes the activations of a fixed point tanh nonlinear layer. - * @ingroup layers_nl - * @param layer the nonlinear (nl) layer - */ -AI_INTERNAL_API -void forward_tanh_fixed(ai_layer *pLayer); - -/*! - * @brief Computes the activations of a error function (erf) layer. - * @ingroup layers_nl - * @param layer the nonlinear (nl) layer - */ -AI_INTERNAL_API -void forward_erf(ai_layer* layer); - -/*! - * @brief Computes the activations of a natural logarithm (log) layer. - * @ingroup layers_nl - * @param layer the nonlinear (nl) layer - */ -AI_INTERNAL_API -void forward_log(ai_layer* layer); - -/*! - * @brief Computes the activations of a reciprocal square root (rsqrt) layer. - * @ingroup layers_nl - * @param layer the nonlinear (nl) layer - */ -AI_INTERNAL_API -void forward_rsqrt(ai_layer* layer); - -/*! - * @brief Computes the activations of an absolute value (abs) layer. - * @ingroup layers_nl - * @param layer the nonlinear (nl) layer - */ -AI_INTERNAL_API -void forward_abs(ai_layer* layer); - -/*! - * @brief Computes the activations of a ceil layer. - * @ingroup layers_nl - * @param layer the nonlinear (nl) layer - */ -AI_INTERNAL_API -void forward_ceil(ai_layer* layer); - -/*! - * @brief Computes the activations of a floor layer. - * @ingroup layers_nl - * @param layer the nonlinear (nl) layer - */ -AI_INTERNAL_API -void forward_floor(ai_layer* layer); - -/*! - * @brief Computes the activations of a rounding layer. - * @ingroup layers_nl - * @param layer the nonlinear (nl) layer - */ -AI_INTERNAL_API -void forward_round(ai_layer* layer); - -/*! - * @brief Computes the activations of a sign negation (neg) layer. - * @ingroup layers_nl - * @param layer the nonlinear (nl) layer - */ -AI_INTERNAL_API -void forward_neg(ai_layer* layer); - -/*! - * @brief Computes the activations of a reciprocal layer. - * @ingroup layers_nl - * @param layer the nonlinear (nl) layer - */ -AI_INTERNAL_API -void forward_reciprocal(ai_layer* layer); - -/*! - * @brief Hardmax on an input tensors - * @ingroup layers_generic - * @param layer the hardmax layer - */ -AI_INTERNAL_API -void forward_hardmax(ai_layer* layer); - -/*! - * @brief Computes the activations of a softmax nonlinear layer. - * @ingroup layers_nl - * @param layer the softmax (sm) layer - */ -AI_INTERNAL_API -void forward_sm(ai_layer* layer); - -/*! - * @brief Computes the activations of an integer quantized nonlinear layer. - * Non linear operation is function of used LUT defined through - * (pLayer->nl_params->data) - * @ingroup layers_nl - * @param layer the nonlinear (nl) layer - */ -AI_INTERNAL_API -void forward_nl_integer(ai_layer *pLayer); - -AI_API_DECLARE_END - -#endif /*__LAYERS_NL_H_*/ diff --git a/src/stm32cubeai/AI/Inc/layers_norm.h b/src/stm32cubeai/AI/Inc/layers_norm.h deleted file mode 100755 index c326eb710..000000000 --- a/src/stm32cubeai/AI/Inc/layers_norm.h +++ /dev/null @@ -1,150 +0,0 @@ -/** - ****************************************************************************** - * @file layers_norm.h - * @author AST Embedded Analytics Research Platform - * @date 18-Apr-2018 - * @brief header file of AI platform normalization layers datatypes - ****************************************************************************** - * @attention - * - *

© Copyright (c) 2018 STMicroelectronics. - * All rights reserved.

- * - * This software component is licensed by ST under Ultimate Liberty license - * SLA0044, the "License"; You may not use this file except in compliance with - * the License. You may obtain a copy of the License at: - * www.st.com/SLA0044 - * - ****************************************************************************** - */ -#ifndef __LAYERS_NORM_H_ -#define __LAYERS_NORM_H_ -#pragma once - -#include "layers_common.h" - -/*! - * @defgroup layers_norm Normalization Layers Definitions - * @brief definition - * - */ - -AI_API_DECLARE_BEGIN - -/*! - * @struct ai_layer_bn - * @ingroup layers_norm - * @brief Batch normalization (scale with bias) layer - */ -typedef ai_layer ai_layer_bn; - -/*! - * @struct ai_layer_lrn - * @ingroup layers_norm - * @brief Local Response Normalization layer - * - * Divides each element by a scale factor computed - */ -typedef AI_ALIGNED_TYPE(struct, 4) ai_layer_lrn_ { - AI_LAYER_COMMON_FIELDS_DECLARE - ai_u32 local_size; /*!< size of the normalization window */ - ai_float k; /*!< bias term */ - ai_float alpha; /*!< input scale */ - ai_float beta; /*!< scale exponent */ -} ai_layer_lrn; - -/*! - * @struct ai_layer_norm - * @ingroup layers_norm - * @brief Lp Normalization layer - * - * Normalizes the tensor along the 'axis' direction using the Lp norm. - * Optionally divides the result by the number of the elements. - */ -typedef AI_ALIGNED_TYPE(struct, 4) ai_layer_norm_ { - AI_LAYER_COMMON_FIELDS_DECLARE - ai_shape_type axis; /*! normalization axis */ - ai_float exponent; /*!< normalization exponent p */ - ai_bool scale; /*!< multiplies by the pth root of the number of elements */ -} ai_layer_norm; - - -/*! - * @brief Local response normalization computed on a float array - * @ingroup layers_norm - * @param out opaque handler to float output channel - * @param in opaque handler to float input channel - * @param pad amount of padding for the channels - */ -AI_INTERNAL_API -void func_lrn_array_f32(ai_handle out, const ai_handle in, - const ai_size in_size, const ai_size channel_size, - const ai_i32 pad, const ai_float k, - const ai_float alpha, const ai_float beta); - -/*! - * @brief Lp normalization computed on a float array - * @ingroup layers_norm - * @param out opaque handler to float output channel - * @param in opaque handler to float input channel - * @param exponent p exponent for the Lp normalization - * @param axis_stride stride (in array elements) of the normalization axis - * @param axis_size size of the normalization axis - * @param outer_size number of tensor slices (including the normalization axis) - * on which compute the normalization - */ -AI_INTERNAL_API -void func_norm_array_f32(ai_handle out, const ai_handle in, - const ai_float exponent, - const ai_float norm, - const ai_size axis_stride, - const ai_size axis_size, - const ai_size outer_size); - -/*! - * @brief Fast L2 normalization computed on a float array - * @ingroup layers_norm - * @param out opaque handler to float output channel - * @param in opaque handler to float input channel - * @param axis_size size of the normalization axis - * @param n_el total number of elements in the tensor - */ -AI_INTERNAL_API -void func_norm_l2_fast_array_f32(ai_handle out, const ai_handle in, - const ai_float norm, - const ai_size axis_size, - const ai_size outer_size); - - -/******************************************************************************/ -/* Forward Functions Section */ -/******************************************************************************/ - -/*! - * @brief Computes the activations of a batchnorm (scale + bias) layer. - * @ingroup layers_norm - * @param layer the batch normalization (bn) layer - */ -AI_INTERNAL_API -void forward_bn(ai_layer* layer); - -/*! - * @brief Computes the activations of a Local Response Normalization Layer. - * @ingroup layers_norm - * @param layer the local response normalization (lrn) layer - */ -AI_INTERNAL_API -void forward_lrn(ai_layer* layer); - -/*! - * @brief Computes the activations of a normalization layer. - * @ingroup layers_norm - * @param layer the normalization (norm) layer - */ -AI_INTERNAL_API -void forward_norm(ai_layer* layer); - - -AI_API_DECLARE_END - -#endif /*__LAYERS_NORM_H_*/ diff --git a/src/stm32cubeai/AI/Inc/layers_pool.h b/src/stm32cubeai/AI/Inc/layers_pool.h deleted file mode 100755 index 4f2a8b09d..000000000 --- a/src/stm32cubeai/AI/Inc/layers_pool.h +++ /dev/null @@ -1,285 +0,0 @@ -/** - ****************************************************************************** - * @file layers_pool.h - * @author AST Embedded Analytics Research Platform - * @date 18-Apr-2018 - * @brief header file of AI platform pooling layers datatypes - ****************************************************************************** - * @attention - * - *

© Copyright (c) 2018 STMicroelectronics. - * All rights reserved.

- * - * This software component is licensed by ST under Ultimate Liberty license - * SLA0044, the "License"; You may not use this file except in compliance with - * the License. You may obtain a copy of the License at: - * www.st.com/SLA0044 - * - ****************************************************************************** - */ -#ifndef __LAYERS_POOL_H_ -#define __LAYERS_POOL_H_ -#pragma once - -#include "layers_common.h" - -/*! - * @defgroup layers_pool Pooling Layers Definitions - * @brief definition - * - */ - -AI_API_DECLARE_BEGIN - -/*! - * @struct ai_layer_pool - * @ingroup layers_pool - * @brief Pooling layer - * - * The type of pooling function is handled by the specific forward function - * @ref forward_pool - */ -typedef AI_ALIGNED_TYPE(struct, 4) ai_layer_pool_ { - AI_LAYER_COMMON_FIELDS_DECLARE - ai_shape_2d pool_size; /*!< pooling size */ - ai_shape_2d pool_stride; /*!< pooling stride */ - ai_shape pool_pad; /*!< pooling pad, y,x border sizes */ - ai_u8 count_include_pad; /*!< include pad flag */ -} ai_layer_pool; - - -/*! - * @typedef (*func_pool) - * @ingroup layers_pool - * @brief Fuction pointer for generic pooling transform - * this function pointer abstracts a generic pooling layer. - * see @ref pool_func_ap_array_f32 as examples - */ -typedef void (*func_pool)(ai_handle in, - const ai_u16 dim_im_in_x, const ai_u16 dim_im_in_y, - const ai_u16 ch_im_in, - const ai_u16 dim_kernel_x, const ai_u16 dim_kernel_y, - const ai_u16 padding_x, const ai_u16 padding_y, - const ai_u16 stride_x, const ai_u16 stride_y, - const ai_u16 dim_im_out_x, const ai_u16 dim_im_out_y, - ai_handle out); - -/*! - * @brief Max Pooling on a float data array - * @ingroup layers_pool - * @param in opaque handler to input data to process - * @param dim_im_in_x input feature map width - * @param dim_im_in_y input feature map height - * @param ch_im_in number of input channels - * @param dim_kernel_x kernel width - * @param dim_kernel_y kernel height - * @param padding_x right padding value - * @param padding_y top padding value - * @param stride_x stride value on x dimension - * @param stride_y stride value on y dimension - * @param dim_im_out_x output feature map width - * @param dim_im_out_y output feature map height - * @param out opaque handler to scratch memory - * @param out opaque handler to output data - */ -AI_INTERNAL_API -void pool_func_mp_array_f32(ai_handle in, - const ai_u16 dim_im_in_x, const ai_u16 dim_im_in_y, - const ai_u16 ch_im_in, - const ai_u16 dim_kernel_x, const ai_u16 dim_kernel_y, - const ai_u16 padding_x, const ai_u16 padding_y, - const ai_u16 stride_x, const ai_u16 stride_y, - const ai_u16 dim_im_out_x, const ai_u16 dim_im_out_y, - ai_handle out); - -/*! - * @brief Max Pooling on a 8/16 bits fixed point data array - * @ingroup layers_pool - * @param in opaque handler to input data to process - * @param dim_im_in_x input feature map width - * @param dim_im_in_y input feature map height - * @param ch_im_in number of input channels - * @param dim_kernel_x kernel width - * @param dim_kernel_y kernel height - * @param padding_x right padding value - * @param padding_y top padding value - * @param stride_x stride value on x dimension - * @param stride_y stride value on y dimension - * @param dim_im_out_x output feature map width - * @param dim_im_out_y output feature map height - * @param out opaque handler to output data - */ -AI_INTERNAL_API -void pool_func_mp_array_fixed(ai_handle in, - const ai_u16 dim_im_in_x, const ai_u16 dim_im_in_y, - const ai_u16 ch_im_in, - const ai_u16 dim_kernel_x, const ai_u16 dim_kernel_y, - const ai_u16 padding_x, const ai_u16 padding_y, - const ai_u16 stride_x, const ai_u16 stride_y, - const ai_u16 dim_im_out_x, const ai_u16 dim_im_out_y, - ai_handle out); - -/*! - * @brief Max Pooling on a 8-bits integer quantized data array - * @ingroup layers_pool - * @param in opaque handler to input data to process - * @param dim_im_in_x input feature map width - * @param dim_im_in_y input feature map height - * @param ch_im_in number of input channels - * @param dim_kernel_x kernel width - * @param dim_kernel_y kernel height - * @param padding_x right padding value - * @param padding_y top padding value - * @param stride_x stride value on x dimension - * @param stride_y stride value on y dimension - * @param dim_im_out_x output feature map width - * @param dim_im_out_y output feature map height - * @param out opaque handler to output data - */ -AI_INTERNAL_API -void pool_func_mp_array_integer(ai_handle in, - const ai_u16 dim_im_in_x, const ai_u16 dim_im_in_y, - const ai_u16 ch_im_in, - const ai_u16 dim_kernel_x, const ai_u16 dim_kernel_y, - const ai_u16 padding_x, const ai_u16 padding_y, - const ai_u16 stride_x, const ai_u16 stride_y, - const ai_u16 dim_im_out_x, const ai_u16 dim_im_out_y, - ai_handle out); - -/*! - * @brief Average Pooling on a float data array - * @ingroup layers_pool - * @param in opaque handler to input data to process - * @param dim_im_in_x input feature map width - * @param dim_im_in_y input feature map height - * @param ch_im_in number of input channels - * @param dim_kernel_x kernel width - * @param dim_kernel_y kernel height - * @param padding_x right padding value - * @param padding_y top padding value - * @param stride_x stride value on x dimension - * @param stride_y stride value on y dimension - * @param dim_im_out_x output feature map width - * @param dim_im_out_y output feature map height - * @param out opaque handler to scratch memory - */ -AI_INTERNAL_API -void pool_func_ap_array_f32(ai_handle in, - const ai_u16 dim_im_in_x, const ai_u16 dim_im_in_y, - const ai_u16 ch_im_in, - const ai_u16 dim_kernel_x, const ai_u16 dim_kernel_y, - const ai_u16 padding_x, const ai_u16 padding_y, - const ai_u16 stride_x, const ai_u16 stride_y, - const ai_u16 dim_im_out_x, const ai_u16 dim_im_out_y, - ai_handle out); - -/*! - * @brief Average Pooling on a 8/16 bits fixed point data array - * @ingroup layers_pool - * @param in opaque handler to input data to process - * @param dim_im_in_x input feature map width - * @param dim_im_in_y input feature map height - * @param ch_im_in number of input channels - * @param dim_kernel_x kernel width - * @param dim_kernel_y kernel height - * @param padding_x right padding value - * @param padding_y top padding value - * @param stride_x stride value on x dimension - * @param stride_y stride value on y dimension - * @param dim_im_out_x output feature map width - * @param dim_im_out_y output feature map height - * @param out opaque handler to scratch memory - */ -AI_INTERNAL_API -void pool_func_ap_array_fixed(ai_handle in, - const ai_u16 dim_im_in_x, const ai_u16 dim_im_in_y, - const ai_u16 ch_im_in, - const ai_u16 dim_kernel_x, const ai_u16 dim_kernel_y, - const ai_u16 padding_x, const ai_u16 padding_y, - const ai_u16 stride_x, const ai_u16 stride_y, - const ai_u16 dim_im_out_x, const ai_u16 dim_im_out_y, - ai_handle out); - - /*! - * @brief Average Pooling on a 8-bits integer quantized data array - * @ingroup layers_pool - * @param in opaque handler to input data to process - * @param dim_im_in_x input feature map width - * @param dim_im_in_y input feature map height - * @param ch_im_in number of input channels - * @param dim_kernel_x kernel width - * @param dim_kernel_y kernel height - * @param padding_x right padding value - * @param padding_y top padding value - * @param stride_x stride value on x dimension - * @param stride_y stride value on y dimension - * @param dim_im_out_x output feature map width - * @param dim_im_out_y output feature map height - * @param out opaque handler to scratch memory - */ -AI_INTERNAL_API -void pool_func_ap_array_integer(ai_handle in, - const ai_u16 dim_im_in_x, const ai_u16 dim_im_in_y, - const ai_u16 ch_im_in, - const ai_u16 dim_kernel_x, const ai_u16 dim_kernel_y, - const ai_u16 padding_x, const ai_u16 padding_y, - const ai_u16 stride_x, const ai_u16 stride_y, - const ai_u16 dim_im_out_x, const ai_u16 dim_im_out_y, - ai_handle out); - - -/******************************************************************************/ -/* Forward Functions Section */ -/******************************************************************************/ - -/*! - * @brief Computes the activations of a max pooling layer. - * @ingroup layers_pool - * @param layer the pooling (pool) layer - */ -AI_INTERNAL_API -void forward_mp(ai_layer* layer); - -/*! - * @brief Computes the activations of a fixed point max pooling layer. - * @ingroup layers_pool - * @param layer the pooling (pool) layer - */ -AI_INTERNAL_API -void forward_mp_fixed(ai_layer *pLayer); - -/*! - * @brief Computes the activations of an integer-quantized max pooling layer. - * @ingroup layers_pool - * @param layer the pooling (pool) layer - */ -AI_INTERNAL_API -void forward_mp_integer(ai_layer *pLayer); - -/*! - * @brief Computes the activations of an average pooling layer. - * @ingroup layers_pool - * @param layer the pooling (pool) layer - */ -AI_INTERNAL_API -void forward_ap(ai_layer* layer); - -/*! - * @brief Computes the activations of a fixed point average pooling layer. - * @ingroup layers_pool - * @param layer the pooling (pool) layer - */ -AI_INTERNAL_API -void forward_ap_fixed(ai_layer *pLayer); - -/*! - * @brief Computes the activations of an integer-quantized average pooling layer. - * @ingroup layers_pool - * @param layer the pooling (pool) layer - */ -AI_INTERNAL_API -void forward_ap_integer(ai_layer *pLayer); - -AI_API_DECLARE_END - -#endif /*__LAYERS_POOL_H_*/ diff --git a/src/stm32cubeai/AI/Inc/layers_rnn.h b/src/stm32cubeai/AI/Inc/layers_rnn.h deleted file mode 100755 index 6098628ca..000000000 --- a/src/stm32cubeai/AI/Inc/layers_rnn.h +++ /dev/null @@ -1,110 +0,0 @@ -/** - ****************************************************************************** - * @file layers_rnn.h - * @author AST Embedded Analytics Research Platform - * @date 18-May-2018 - * @brief header file of RNN layers - ****************************************************************************** - * @attention - * - *

© Copyright (c) 2018 STMicroelectronics. - * All rights reserved.

- * - * This software component is licensed by ST under Ultimate Liberty license - * SLA0044, the "License"; You may not use this file except in compliance with - * the License. You may obtain a copy of the License at: - * www.st.com/SLA0044 - * - ****************************************************************************** - */ -#ifndef __LAYERS_RNN_H_ -#define __LAYERS_RNN_H_ -#pragma once - -#include "layers_common.h" - -AI_API_DECLARE_BEGIN - -/*! - * @struct ai_layer_lstm - * @ingroup layers - * @brief LSTM layer with generic nonlinearities and peephole connections - */ -typedef AI_ALIGNED_TYPE(struct, 4) ai_layer_lstm_ { - AI_LAYER_COMMON_FIELDS_DECLARE - ai_size n_units; /**< size of the hidden RNN state */ - func_nl_el activation_nl; /**< activation nonlinearity (input to cell) */ - func_nl_el recurrent_nl; /**< recurrent nonlinearity (hidden to cell) */ - func_nl_el out_nl; /**< output nonlinearity (cell to hidden) */ - ai_bool go_backwards; /**< process reversed input */ - ai_bool reverse_seq; /**< reverse output sequence */ -} ai_layer_lstm; - - -/*! - * @struct ai_layer_gru - * @ingroup layers - * @brief Gated Recurrent Unit (GRU) layer with generic nonlinearities - */ -typedef AI_ALIGNED_TYPE(struct, 4) ai_layer_gru_ { - AI_LAYER_COMMON_FIELDS_DECLARE - ai_size n_units; /**< size of the hidden RNN state */ - func_nl_el activation_nl; /**< activation nonlinearity (input to cell) */ - func_nl_el recurrent_nl; /**< recurrent nonlinearity (hidden to cell) */ - ai_bool reset_after; - ai_bool go_backwards; /**< process reversed input */ - ai_bool reverse_seq; /**< reverse output sequence */ -} ai_layer_gru; - -/*! - * @brief Computes the activations of a Long-Short Term Memory (LSTM) layer. - * @ingroup layers - * - * Implements a Long-Short Term Layer with peephole connections: - * \f{eqnarray*}{ - * i_t &=& \sigma_a(x_t W_{xi} + h_{t-1} W_{hi} - * + w_{ci} \odot c_{t-1} + b_i)\\ - * f_t &=& \sigma_a(x_t W_{xf} + h_{t-1} W_{hf} - * + w_{cf} \odot c_{t-1} + b_f)\\ - * c_t &=& f_t \odot c_{t - 1} - * + i_t \odot \sigma_r(x_t W_{xc} + h_{t-1} W_{hc} + b_c)\\ - * o_t &=& \sigma_a(x_t W_{xo} + h_{t-1} W_{ho} + w_{co} \odot c_t + b_o)\\ - * h_t &=& o_t \odot \sigma_o(c_t) - * \f} - * where \f$\sigma_a\f$ is the activation nonlinearity, \f$\sigma_r\f$ is the - * recurrent nonlinearity and \f$\sigma_o\f$ is the out nonlinearity. The - * \f$W_x\f$, \f$W_h\f$ and \f$W_c\f$ weights are sliced from the kernel, - * recurrent and peephole weights. - * - * @param layer the LSTM layer - */ -AI_INTERNAL_API -void forward_lstm(ai_layer * layer); - -/*! - * @brief Computes the activations of a Gated Recurrent Unit (GRU) layer. - * @ingroup layers - * - * Implements a Gated Recurrent Unit with the formula: - * \f{eqnarray*}{ - * r_t &=& \sigma_a(x_t W_{xr} + h_{t - 1} W_{hr} + b_r) \\ - * z_t &=& \sigma_a(x_t W_{xz} + h_{t - 1} W_{hz} + b_z) \\ - * c_t &=& \sigma_r(x_t W_{xc} + r_t \odot (h_{t - 1} W_{hc} + b_{hc}) + b_c) - * \qquad \textnormal{when reset after is true} \\ - * c_t &=& \sigma_r(x_t W_{xc} + (r_t \odot h_{t - 1}) W_{hc} + b_{hc} + b_c) - * \qquad \textnormal{when reset after is false (default)} \\ - * h_t &=& (1 - z_t) \odot h_{t - 1} + z_t \odot c_t - * \f} - * where \f$\sigma_a\f$ is the activation nonlinearity and \f$\sigma_r\f$ is - * the recurrent nonlinearity. The weights are sliced from the kernel and - * recurrent weights. - * - * @param layer the GRU layer - */ -AI_INTERNAL_API -void forward_gru(ai_layer * layer); - - -AI_API_DECLARE_END - -#endif /* __LAYERS_RNN_H_ */ diff --git a/src/stm32cubeai/AI/Inc/layers_sm.h b/src/stm32cubeai/AI/Inc/layers_sm.h deleted file mode 100755 index d39cf930e..000000000 --- a/src/stm32cubeai/AI/Inc/layers_sm.h +++ /dev/null @@ -1,80 +0,0 @@ -/** - ****************************************************************************** - * @file layers_sm.h - * @author AST Embedded Analytics Research Platform - * @date 18-Apr-2018 - * @brief header file of AI platform non softmax layer datatype - ****************************************************************************** - * @attention - * - *

© COPYRIGHT(c) 2018 STMicroelectronics

- * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of STMicroelectronics nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - ****************************************************************************** - */ - -#ifndef __LAYERS_SM_H_ -#define __LAYERS_SM_H_ -#pragma once - -#include "layers_common.h" - -/*! - * @defgroup layers SoftMax Layer Definitions - * @brief definition - * - */ - -AI_API_DECLARE_BEGIN - -/*! - * @brief Softmax normalization computed on an array of fixed point channels - * @ingroup layers_sm - * @param out opaque handler to output channel array - * @param in opaque handler to input channel array - * @param in_size total size (number of elements) to process on the input - * @param channel_size number of elements of the input channel - * @param in_channel_step number of elements to move to next input element - * @param out_channel_step number of elements to move to next output element - */ -AI_INTERNAL_API -void sm_func_sm_array_fixed(ai_handle out, const ai_handle in, - const ai_size in_size, - const ai_size channel_size, - const ai_size in_channel_step, - const ai_size out_channel_step); - -/*! - * @brief Computes the activations of a fixed point softmax nonlinear layer. - * @ingroup layers_sm - * @param layer the softmax (sm) layer - */ -AI_INTERNAL_API -void forward_sm_fixed(ai_layer *pLayer); - -AI_API_DECLARE_END - -#endif /*__LAYERS_SM_H_*/ - diff --git a/src/stm32cubeai/AI/Lib/NetworkRuntime410_CM7_GCC.a b/src/stm32cubeai/AI/Lib/NetworkRuntime410_CM7_GCC.a deleted file mode 100755 index 6e59de6a4a23c9946aa9d78d6a5d7879102fcba3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 926524 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
<3-#+lk`ig6+M{!MJ9s{39i*Rv` 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%0AJH@UIGl)M{I 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л8P1Bz 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

@0KMf}m@YHIdCY5Tg z3qSL~p!T$Ma%9NXUh7)bQ zW1A9Na^TNmmlvK4+S!bW^=AKft5_z@9rM2m-{;c6B=TtBM=%2kwbO!PS+SEHG^}Eq7c{ot+hlT*C+O~GodbN%E2B41r z)sTA&@NokoU#97CmfW2PL|yA3j2sxVeHk$F3Sf5IfF!ea4hUpgu@on(&sgrvpL!Br zEP#+NbQ40Z_GwgvkpD}r@|4_>?|2Z1<0vmXj?omnJxttjyWwZKs$Qw;%G>2H}~RQ1?(}kldo?kj|Xc8?>oAQ-9eb{(TQ{@@?58a3+p?K-f*R5@@?!f?S%u-jbd= z0(fnGHl5pc;biFI!xGn|`YQNhf5-u@FJ|NAR!!rxd^RE2#eB!)vc17&z2!m_+M3|a zXU=vKl}W1)?&yWT5(Uw*;^^qI*hkGp9e4*j#_UknZ?$s!lYt}4+NCu+tjDlFpiA(E zeW-H>ZaL3~`fY*_b)54LDfh#N`X-!^{~SKlSr{L`SM-~%jPjcfTz|@^`%QlWe$$hL zb6avcp{HJOru^_fAGa72#;; ze`L`2RAd7=w-aB})5O{O^HX}M4XK|VG+)Di+rtZ0A>tst$+`8W41QLz5ipM zj=RyaNAMGnW=h=0;4z{CdLkZcx6R9iq`eg3xYCXYv4};WID0l-;ZrG(AvP?0_eb-# zl1))`?a7s$Bu^ZYE+=qxk;{|3Zw`~c$p^$agFFANQ(Vgm!?Kj8bB{;(nLG=qxsxf%i%}=hMg-Mhq7N@>|8ie zM13IYdObIC>EbJ4r`OMr~Yn|W-y9PoKN zIwAO6>~1LdydHSo+yRWSe^{~b`R@Q5y2Xb2slw;Jq95NdO!#~+=xEi%B*Nmc@cC1K zlf^os74Ku=^H$Ie2R?rebi2e(qpq>=c|IWJ;lSs&fNnVO`FhX|2R{GTsD8!iAvhl1 z%jeFXHvpfTE{dPez9s^Y4$XhuHgswsLN*0Zm6T7_|RZml>LTA*U1zh^2lW8%(tO* zO+{&mb<2h|75K}2^U8kn=#tV6n?Hv?>`#NkHah#pmfv5 z0la)I4T{jr@Te}8)wN~Lye}UNAMS+55%6hbH6BO6VNoAPz>7XF_7+FL@47^D7e~P3 z2>9pSg%La2RrYmX>WPrZFyda9`+ucGW@MwibkiyX_}F|UEYH_1BC5aOQIE@dRdaIV z=oX;hE_hqE8_Mx5zER;!1!BpZlCu0V*2}}EoQ$RJOK*|-RI1ybrrha(q5X{j z^DKvT?6(85CkndfOkWV(ai%M%J+mPA*e6rq7q6o1k3sDxuuYys5miqHwZSPN^)39| z1;K|uG8^9vYCjqu(j|-!DQ|fjzK{*==&_yby{#Q>0R=1SZr_&pI$6yEf%VSq<6cV* zNbWu8)9Iv5BhiB~q)oU!eSB+jNP7#t*;Jr;S})Phg+(c7Uo#tVcQ5Wnh;Xvq+?ufVq9AIw`7@#U0ll| zww^5ujWW%&-V#a}CvVOaya@6EiAG*8A+N41$&0w0EmeXq*9XmV_#Fg&uPrpnANK1C z+H}3(Tacb2?SsO#$f&51TDG6D9_E_l2NXc#u^P>I7q_C8-$QGs_eKDEXe(qz2X z$!5sAxcWj?7}6Kd&*8nzeVqOgGd$uluE7>c^k=86Hws=tF&94uhN}@UT)eSOS@Ugh z_=gyS-b>txcbCgxtiWMiGroENOX_bi7AI{4PFgn%oHTowIO(mRqZJdAcpHn8HY5ySqeLsx#p0yU zgboWQ{b$fQ#ZIHHCAg0^Grk76*Klyse9#RCC;cwyhJ%wn4LV{EvSy9NNk!mOKua%* zlg_&4+Ayqoah!AoIz{^0;iNyuOAYXL?>SPwiivR2Ux^u9rC9!GT$HB&%|Z2paZzG7 zUsOF!q3EIFFW9kP5uEh%*bh^5%?nx%e^#jU5}FR@&z<#EK}+K%!*TZ%arYFfE{Szs z959UorWKp%{J{6165PBpXVJ>F>o%>wXB8rqRa{yY6NB~6xDvwW0p6Y=1mY^22RAll ztIDqgC@c<`0-y~4Y~HkHM)|7m!?N^BSeQ6qx^DH#{M!a}lUSrn7N#yxu)`yTA(^_j@0><%CtU<>iUkN?%!=mY)W|jm=Ly3)g=qc&q^jKgYpj*zFQQF0$Hgd*^>GM*cj1=IM!r|ZpXw~=UMefe)%hM%yDceJtyK@>;K!6& z-;KIaFsamf^SkAFQWvY+p8E{{oFxLy!myOH=^7L2lNyp;7>|zm&pH5e!Px{W2E6B% zTXlO5T9ay%YhXI)O~TQA1~`gi(uUNsm1X?w6M-e!S{&bZ0PNye9cots=&B1yJWIQE zOT+N%!vMP;2`=u|EPgYn`{-m)7X)zYE9m~##09~J&JtkzMo@G1k3r2R{{g@dFm1w= zkk0ZS0hyPdWj0O^DHEn6SWgGcN%5aLV6f`|gUJY@y-)YL0T9>p%2|D!4^ZF}FQsp+ z90geS7YMyK8f}>Q@o?rK(aj2Q>7aaKMkT23QneCn2pR;nlk{M$?w|V9icuknB|>)> zU_`a5^`msNaWp7EWjWn>w-qbJ4jEWxa+j`=V9rG>eT;4o-sQbzA)^VVqUp&Eya3A< z8j@?dfMmpI@BBVa)7~p#0xZiA_F;^!21eo2@ccKDT?DM92$1X|LvoD-Pf#B$b3~WU zMLm?T2>my24kb|!Q}j7{ug*oSMz=&g>@dqBP+dw&vJe1CY?J1VYbZ2wwL1XyjybHb z>KZexwBjYi$+oNf5;^nV=XlDx%ZjyE=3B=B;FQ^k2b|UfXN5HZrlP?2Fd~8%p&lr< zb}OvMj^It6_#@WLY#adE6@W4y{s^m>@n%r*(I3G>x?WxfXfxx#`&V$hu!6r*s$Nex zKxXgX>f`QOP)Vyc3Up>Zxg()vUL|T?_!i)F0xXpjcq&6IL0*{#%71hw?1RbzGp6c- zsde$#G6H-@ujX>@2T-Z?(!AU+fWB#EsQ1!*+bslQ9x|klDKTmRWvY5*s>c9l$^`(J z{?8{kbN=OpGbd9&kwh3m?$B-%Hc9^>x+@19M#vQ>LWH;qfCr!~0X+hg^!e;QFXlGk zH|X_B!!aihU_Ih2l574b2#B#C0a&Xa299~{FmcQx(9u$f2@4{mSR6BFm^fzsFmcQ! zpxY^S8g(UZz~c9(*FiTN9P_WB8xD^7KcE{9j=B6(aLl1S?amq6U&6du*ACm>vj71a zkiK>}<|}xq0p9LCcT#xG@E75je;$-qvHus9CqeLjRG$1HNCz52jgl#%@`Ph1#^g=N zQ&BOr3|~5~3DeK58_Tzl(dUrHpZ1Efd)93(E!tdaU$tq~>he-D%iLPD@U}b{Z*JIp z_ZIwLcuD;6;^aA+wtv6q?s-v$pzF%Z2XZB)!x_z`vKF<@&HM84&r7pBaa+>3EosdE zYa-0o?{zlrxwjN(*QbVJ7w0VQO(E`0Ar6hg$;>UA365L4YRlGDo9-@IY1z1D%lgs{ zml-{dm@LMj(Ks}^e)g=D7ck0>aLL!rmh@afoo7n@)W*|+V~!aOh--|~#xm#A6pell zbJYi!gH1-%YKIUrn195~2PLrFyPeb2Qq1_az+Qb@V3#8sk(Ph!mO9A`z>RscU0jHN zztF(>{==SFYt~DAW+wZ2g7XN#91h^sF6O|=>NG}RV+O27)3P@LTH0$1x8`imaDt{- zf^+-mL!W?1^9g{qc+~Uug6?vy(l1dS3MAVz>fxvL4D+ctf`i7wBZK8>^4#jNUR9QB z0St)mfA5}P`L}Lm{(|6xAHo0X1OhX0{~`R`-urq`N7ogw>iZDZj^im$7JgLL71Ysn z@!NpElG(41c&y22?UioX1bUh%U+ErSGQxr9EYq~~)J+b0W|w2U_O}jxrrG$n&K1T( zof-9NjD1%zy%C+KhewLyMIEy-3r;=WxA-BN4|4*}a%22{osY@szh2+hrbqk1;k?4NsoTj1A>W$?8)lId^Q z(bm@#S?4B(5oZ^|uW2SqoTeM|=q=2-|C&NR2T-GD^}1Tt@Jra8Ccs1N?!YJ$)-4oI*>cWmaY)xcwS0a@j4p z^3GY-W!CwEb@UW(Hha-pXr0tiAM*QWTa`{_{kunKy_jF&!2Eg_8382w`Z^u3dqrMv zrhGcpP&t)E^1}5!a0>bBIMu0jtv4J`{iS7h?ok>AJA^TgXe=?P8k%xzEO<-j?o%}O zLwIZK8}ePC%W6n)(Mr7yYv!p=Y0D!}9E|rWYc)<~Lzgw7OmAhqdRcDS17#h6ft7n_ zH>(a@KjvVoYVW(Ly5>WzH$AO;@+fS_v^m5FW~Fs_7|aMnb;vC9(NR5CzP3u z(z@n8t^K+_Zbft7i1u@>77OlQ7#)%)H23N3MX<4^Is;(i=Dv~bRClfwwX>-Pr9J=I z$zWTZ)pa@`YhT0)*$Q}LS*k-UcIPTv?W<+p?k4s4Q#eGHQUe3J$wRdw9G1nw`HsmI2E8? zW|Soou?Si@^3&cXo~v_QIoB z7-+YJQvEi|3cfhi33}B_v|KBv%FWP9t)KsXx+uBx~7AzPd*J# z_v+`N0y-U7BFLYu#wh8NAC@o=hE4_5kTTaqe)Fn7grtc`A$bN#AkeJ{(}X2aS5SQh zl8U6!iV2WLo#5srZpfqJzgX{k`lwX~zfVUYKf^M~V$nb*O^wK;X^=_B(@E}NS3xFC z7i7|tK82R#QaVm6H22Nur!gBrCCDbCKyA+(f_$3SCBfN`6-f@ z!*WO|)@aOm=mTCVZMg%|YO6uI57OeBB(tQAqQqKZknWK}xhP64scVrzDySP-W11kl zqz#1zsi3l)3&|yEx!)X)T@aREI5ol1SrU?4g`rXJlf+sc8ubC4Em>rdwvg<)(X!aG z&=To?3`wy5Hph?@lQxnBi;QHFBa5YcRhiNHh<_ z-<9+`>3yrjs>BJE-+I9TXULPwv@v0cHf?N$Wm;K4kZGhG=3n27-;&ouvRN!o`8XXE z!Z@olvSU&u%6t~f@iZe&*$m{&M#@97O_6o2XSamXohcE?7Cud53#I!PS{4bC4Rfq{ zfh3!U?IAfV-S=7K+6RY*C)duM{mmg}N{v=ba@7)!(dTxc^j}1rZqfwgCT$+dsrwz$ zC*&77WdZ%0;L`-!NjkSc3agy!a9vfpYV|rMp;H}sv!>6?X7c_hW=t_cd6SA$^CKh) zl0;dGBvq0oH3(YDRFDtp+T94foEmMYiDP56|O_$>gh6kOHdQj|+ba8Oi zGU!Z4HFPV>@QF>ay34nryL@^Wy31X|)LpiMjuui(vdB%W?lKWGEY=Z;cprNPV-)Cy z3c`6Co{4_F4AAY2^c8(6K?cjypPm5SaCDb1fX;-c=*)yT&vd0eF!y#`gmemYH;b95 zs|)wh{my_I(S))g&S1=&HKeZ^XehIV!xrK1xpSb*M4ETaykYx#Uqh??HPl`HJ6>vF z@q5pm7G5*_MY_v(2IWJZOCYoxa^f2{-0qwb*hap*PNz!4AHCho}t!mj%S z2Ke5#fXuuhZ-jNLUbT-+l=&$>q}DvqC8;A#U3q0)fNQS{Na6Qore*G!h28u@OSjB2 zZOjrxmwdLBbfS*d+n-h)o?ngr?c|N+THyJ(y05h$YUCn{8i}JBKt!+0Iu+zYbW9@` zI+>F}8C{=P5ZoCo=)QI`dC$RpACJ?*sWc7 zL$~e*KXAAv@&MyqW%*sVPSERg1^F|->z=+L8M@AIEgcVC=VPDT?D%6)`N@y*wguhB zr9TcRghL;HfgbCT&WVkatw%94O*o=Jo>z3Xf(~J(7|m2cw^TvzrH59RbhWcnNb~i0 z>oI61a&Md&`8>|Fg^;FnF=6f?kV zV7?A`C2wMd&|K$oNzhVqz6Yd#pf$MGa~Tc5(YEbrB{S5tT9fBPig zkXo-ifM+~6TE3UZe4Lt1rTD$&`d#pN{+!_P{Ox?@sae)*`?a`$5DK1wMkNbnwulxt zlXY3IgBI6gonj?TF6nW-f*w~+THDX5#r@Atbpz?}=UIMXsmVWbisBfQc`#a&rjd7* z7#>M!%H?YxgC4i37@p#7ILxCbJ??bq9C)9I8^StZ6+Cq5RfT2H z%sBZbS;Te%{W<5S0?RiaY+VV>%y`vvupJc3``K?N>tYf)+Gk zA6*QZ7ba+4$UE3|g6@Su_kzf=5xTJcm^H32FhOTC0{W2=(2rb=XvHS)6ze>z61r0z z>?@XZsI9B4$~~-kt96Gp$vVIKbRgL)$(Y+THuzBARs(66IjphHXG08V8Czn(d`@}y z2y`RgSCGc{3Ft?h7E3CQYLQnhlr*BmO*-GSkSc@jsf@I~H(Jx6^?k1sbHJ1hiDOn6 zmE`5>CR<46od>CD4(bHmIQfQpzLV8)4Rc*e#HWBSwQN}LV9#R@)|0N+qgNx>VInQB zLeTP#ehND}ThpKbb)xMLDH>RSbY(9xD4^}dPOrZy74pPZkKMiM{(t<{+|A7F>I5fA zA;lh&6}LjmOY-NSDOLuBWrqXS4pSWz^ZKA^g*@eYEjH2C`g}6V?`1zf1VcPPq|0aP-5U+dvmKXuO`P2qoof5&%*l4BS;_U=oUI? zeH2yvK4l&Drbp+bm>z=sY38A06eZB;+G99g7%g)~p+q*Q^HIHzZACbKf=41wRt}g-@moUi-=3(MZc=kMfZhy## zwK%mmedCONpL!S2=gyfmFRb7-UEHVMeGq6!U%RuYZoJe0bM~HlmfkXwNT1s#W^g5+ zdap(0NuN77wzpD<6WPcgRKp)FkFFw@Ye0;ui{p`}E%MsZaTB{*Wo(ep)<}-%k z9?F$oQITK=Q?$Nx{pQk&fy1QK!6iB>I?tN(<*QIHKAG`Tpz%|n@l&8HHN4-pc-p}^$}iw6e#WZDvza`S@0>5b`%=(Z~`*anShgR@(#`_@uXPwF9OXx zF7fDJwA25iqjCJZ-EUGo6x2~k|C$Z_JBUm;#X=pG z_}}}nVL%;T&QY_R_0y+`ipnCB>7V0Piod`(~otR>wj=Mqkuvi&& zjfFY_pc@X0j^ZYd5XBbKQou8`<Ie z17*GEo{1tRBxG<@Ru%hAR6VWE3FMcEjEns1QT0*)Z|@-gWK{h>2G#3W2>J1}L4~9k z)Pe6M%v`0wG^~e(mjgj&Ox`0zKF#Tr+W-3Z6D~e{b=_RGB zx7=9-K3QKna~7K}6weu4jI2<6&EVp>Y$$Z6V%3JSwF98ehVml#G8@Q)4Yv&BHm|#L z{l;}A0|oT-CBlH_Uvur3j{#kD+2RmT90H0%Kye6Y+9K0s|MhYK$2=mo5k6WFhk!0J zP2w--c#MQ;OJXEf#Klt_0*XUG|JNX(qdmpyX@B?U^!Dh3iYCMlu*#1Asr6^MjviB* z+5c-tb?!4gX7#r_sXpt}bx$Y4P@DOA$5n80^IY!y<8$m=4QAsWw-yB- z__$iALH^!5^XDJ0uu~0{9i=;=?2LWxm_p-UJKNs%SFx;6N4Q-TwR`W|tphEeMav7$ z{Npgn)8A?xX!jUe6WUE5XqU>u?ZS6G+NCkiKE<+rE3~fZm{B>?y3~O2eR2;*HOaaj zBOhu106o0WF}c!CH6P;>ScTeg)|vJVl{p40?k8Fm_NOWr8rBN;I{V)%t%e+dW*Xi> zV)sVgqCU2tk6#2;bUzOZ{rrjM=#w8}v|=yMM)mS9D4%Ez_wra&FMk$#FuFc}dy3P{J(9Gx zoBb4f97|sa_hABWRLoL%#Uo%#dBE&XB-utp5jN2 z^_Uxw|K3&ujl|TGsV3vd_8wks@7bv?F+Pj8$nL4a*j`Rcz}VVbX>??u`d^)G|ByXu zhyB7p`_v+}?-bgn-j4MY$Fxr^ntCKcKOgll^kMHY3A0t)^P{wvd#cm!?%A0JD)r1B zhq?`;qB$Ap7beSMzei=(M1k`a9mxU73bXN!?;`rcT>)?o^N(_%OjBq~S&1?Y)qj_2 zS5T>u%I>1F+o??R_fGo&d@4ziQ0xK|Y$*pWTFLGBxBYUt3L*GUOavcTl76s5@u2)6 z*~8Lm?lDO*>Mn?(0yYznD|{)b4H$t4Mo2)m0ICV_7H%1XBYHBtV#o*p6wt-1C_j>2 zR;YLi^$|&geB>l;+aY^U`Vd~rl2j?L=6Lx|PO&a&o1&Ui?Bt3;!r?s#Ams2$mvh#m zhejaH&_mlYXlMXEg`oj7yqrUeW(dNUa+3aOhx9@2A<0@m>i_nuVwxRT@(Dx1LViB* zT(BOTD!HKj;19rwYOu>+B3CAnAt58++yat@6_QaN(;=tp5Rmm}f!bf8HewQ9Q-Ej1 z;s9>40i{v@0%PM!&~dC)VI~IpJhFcJNmTvSRyG^Gz&}*so|MIaGT$fo?eMy%p7- z$Ol8U_b%v$GcRi(6~*zM9=H_}wWppjd*1wr+Z@4*&c&=UubC|d6uG#rB7nt3>bJ@qK|{Y% zbrr%;qral3nKTd{R1TE&p8Hi4F=-%3!yqQI#XKcugsX!6F)B|Qg28b^l!7lFYX2qd zTk-+lU; zI4&Q@y_%mdYvL-3f;+fn%*H!6!e~2Y>d_YRmUi;I!rA7kjHl zzI8Iw$|kW1V}p)9a=Uw2bwC|+(K@o_G#;Re3UKXIUa2!)~dClPg3y)(vx~x?MaSlB8ZbrkDUKIyR+F{5?CyF zJ39}%GvCa+-^_gPHyif%{lE9!{OOp%UkJG3f|$XreK%*g)_|P(H=rkUlMma$f4{Raqeb3(AT>-%+v zSyuJ_ElJ3y-1=&gvfk~Yunny}CR1yV8G#z`D-7qp5rG64dkgJJ;iVC3;dx9WN7$S> zY1biS1qI5$ei)-h9f70l-5*H*ZUUybrgQmW$Ch=_B2tyA`KR(xfR<-u-*IbXs4^C49qm$ zn%ZoPpxB;;kUAJ2cp_Wio_E^yqHcu|pVOmeqiE>;q!Vq3JIX$q-+i+wvA&wsu-imS zT$@l@tmKpVLUHU^3TuA57;CZb&z`&Kq)vro3$ZmeJB7};1$NHM=WfPcdvk@&P7~5; zU$LSoL&~&VYE$e|VUjxbG2i6#?5Ew7dg)v_u#(zd(%^;Lyl$fDN|!&%P2f+@HzZWtu>3isCD-5_E66l&npqYhFMMs zwswRrVJ}&K-eYDz@6jn!pMD4d&hxv?3_jofF8VwAdR>0^EcpFF1YxQb;qx0Pa8nxc zT)&H6rJE^vD+@iW&eX3nrC@)GsL%RSrw*Y}uC_pOJ$g!q0>bN}?iYWee;YpQLCB8n zSHo{Q(aiLsIcvTyv11R<@pg__)); z!@CGYGUligA?o1+2imd#q2U)=B=5j8M)Hg=_(@#Xi~R~kt&^eMm4k|YYInuS@d^qp zpCVF_koVivE%g^{<1iC@s5M(HIT%}Axw_!mMUxv^`93w(aB@(%7i z6Xn6Tz8u;XWdO>z3=JbvP^@fE@wV@TC+xf??;z2qE>OL3VOG)0)nKwhutt$6z-cw4IhUYkH`ZQXUdXR7FKl7Tri8Zm)j*zlGgq2d?_;bi{ zA1fW&rIq5AQ~ev!#lCgy^vlE$A5QE%H0|IlJbUrtfzQq6zkVU}h0^J0?C)so?`Z7r zXzcH`rDcVVsJQv|xq(o{@-TuA>qh6dj|_JqMV}@eEk_K8qVkeeUu#c_ikl1bg1T`O zqTVyy-#34=eD@%#f#2?J6RvdPWqE*40?5f=fG0g3L#ZwSasHUo+~ZWyUd1D-U2MW+ zo=x)T2$TXBvVR_ymR?j?N`N$OaC3jm;4e<$nhOZWo&`&j2$t4ZOA|<#OPeJ9>BJ3p@P&!=t|AvI4vPdmZIzD^tjGC z);AAWj$;69sKeF;*b0bi^(;gTU%`R}{aZ+sK+)e#{yoyv$3D!wU2 zP&Y3C#Pg2@q#?8IZkD2PkV0_3J+A9M`Bq3`>23tz6%T z7`%>gO=`p=o|HUp*J44nT-S7~sLmYMtU-Lw^m1MEB2hDMT#NQ(k!nWrI4RoaVo|#| zzBy@sdaVzm*4UDyNX7B>9$S1}hQKZNMfX%7HnBpAO&njJ)S#}NB4xL|)t2Pj*Vt%_ z--&A+r6O?46iq`omSy0s9Lw!^9twO=I|g7>cxpRuXn-fB-h-Y|kc7OB=qdZTCOl6P zBCYkr^YMsLjf~XomfB+ib8MC(#Ug{a1$BBTDrgKM#$6=K|9;77|Wej*?9 z^l0GISv;bM_RK7&VFGy3kHQ}!6uy8kcq;O7t}CZO1GN7{_{BqhNylFJY+{!LPBSEM znks?QBU=62NrK`girEa$^k_vDGb4)hd`wYL@i=0XkIc8DAG*-{UG#8Hp*)a z0ijF3G7w5!V^|QH8~Z(FP85WK{fs646SgFw9K3rqzI%Qa0SJwY5QOHyj$9)z@@6;) z{Y``*v^_!)`bvZ#G(QM%%7ByrXSiCoD9G+yAhdD>5DFFPtZYEfz;a#^ni;u@bk}!^ zgg%GnAL^3*XF|!RhP^BIC9FwB`q!W`k>c9G1NkXg2DyvG% zs>(_)wVt#naHfl-EX|$q4G8dX!CW-Z3Q>(|+4`u)G^#O;#(s$6(IBoA#iOgrRu|?) zpk$2V(Xz^sLQq6gBL>DB{6wZ-k1i5t^Pu z{Lid8{Du_v2-kCyQoA#OPdmPaXP2?bUjC_mkGZJN!~O`3+aCp0t1ffTp#C(H2G;Ev zG+>QA)1CJELA_8vXb^fjGve6bmcIP%6kan}d-{;;C8$OpI=vzNy<=|PjyjCwC6&PWE)>cc(kq;6r^|67st*TaX0B zoO$qplT9w`VQe#PN9F)G2dS`nPD3wx3VP9T_11l9d}1RLHD55%)Mtj$F1y{fuc*7w z#QH{)ZnVINWNj*M;?CqO-NnXh;)XU0(Bh+J*lOglH71D>iwh; z^jO%Bn5CWmQ3lc5Do4roDHKnu#w(t?`4gcdY8ObePE z(1HfeD``QQUkfUo^_roSZPYSDTF{sS5AeqQiH*sU7F1o&wVHd3cwTHB(0qE}!zX;Y&z#Am`y}=4b%R?@L+|PF>phpqde6x?Hd)j!`LL7v z?G+v9W5%NH*WHrR(>QYgN>6yjDze@Lku53eUZxq_0kj-AQf;@0y1&7$$0F+Qz>#IJ zH`+z@LrAQ-`@jAA-I$}K?j)ry)VY=l=w@SM!Zn_;UG4n}M(SE9YdJLl|E*%|r=<2Q z5M%ouv~E19p`IiZn6eYhta zY;FM9d^`fMnHnM3%!eJhMqcF2aIm>OLa_O8gkW=bgkaMi1T4=5Hq(Rb&ILBF9RX~D zYtEV(pqfFEd`D1tX3x&f@|mAs;dwpo70Y*Ic06Sw3g((`NjK+vBZcR&kg`66V-nZw z2|4cLm_xg?>Byv2BZ0n)<#Om&T6}8aNB5b+ci}sEALx*-@Szum8BQbll&Yl8r&8Q z;rmCk#iNtx|6fd^Kb^lFfYa7u<6CvWjHX{(jSUK*&3RfSZ`eBkOqQ~tv(ouJrdkB0B-65H)RM3yt%+USo_5~*LVbVeF0PAH@V(9X5~?* z?iK!lgFAoiIT%~+tFeAi352N^jOBouQhhDHJzsnhsP9!k&6Ig@fJ4f`S_x`mI|ynz z?M<$A(j@o{sPYOuMcsFqS>NZLq$5=wxfgQiljffK7y>xUFc$Cn7*`nGvG6rLZH{$jeA5?pn+cmyeOHyd6H-Iu~}4 zOt!uOb~F(>d@02a8M)E1PT1k!c_V`UImqr@D6SuN!%em}1g5vTD=S0thXc_05{3KT zXJltf2yW(#jM<`~+0+%3e&(JZ+`De&eKWEP*HpMM*~>L6 z@9Rg9=W|{(P-j#`85L1RMU+tyWmH7@CBR-(L>U!PMjkRWDxwVgQwtEh2LDrCJ#FQE ztKDVyKwmlyR2UM|{PNX~sZ*<0m87zwqD4Pgy{4=J+2X27s(!#+*uc)xRV(i?Ngy(LIAv@wzOJ?b&--vKMV z$o<2^zagmFNAWL!&#^kL*V4U1$Z$W~o12#3%^ARZEX={KH~~t?Qu8|UyA>vbsO--< z$R=^3qNJ$Xz-4zN_9;1i$LPULVyVq2DwB|cNHBVrx<2bH>TWPs@t1XM;Vt~cgQYfv z032f#I7gKW)?bv`%%T#uW-pa!yVQnK*PSlkao-*=H0;~s`ctQyud(GEygRS$IIgvw z5{6OgDeiDHuDDsqcI?g7b?STGzn}G#usU&|k3uev?c$K4O4(~^5PCmMd$#wboZt37 zkXF_E+ca-)Ne=jUmUy^~<>SC}=T zQDYM{#f=FywhCQJ$F=-4o~5dfvh*7cSKCIzT5-JEme94K`^~Q3yHvYtPF;6^X6%y}+I*fY&@`1LXm+;^6xOL> zr`~;|>n2drQ3rHVPeMPsUd30o>I@jHYoi}7SaT36JqXIFHv3AgZU@(U0x+dGQ7-~6HGZH1_t{LAGnxhaRU zc*SJUcox&~aDrCUUGeeq{n$H)ueODko%T;UEA02X-tUxKT7jqON`@!OQk(lzfn~&W zu=>8!U^=45Q-?IE5t}|1*`a%TUjq{j$G+Nxj zxc^-K9FFAR4$j`=wD)wD+COr=(`n;B;?KH|jQZSdcoO9M7(@4g?}4-L16FK4(&_2@ z75c~h_d#Bw=YIqLpf|Zm$CJkzB#*W7v5oNBgLvZG$#3H@f>Dfdg;ia)edImzV*95b zc*sMn&%2>I*UPVP(a4W~45SO=6X-eR?bHga?^!(I_&yjYD5$|V0O$TYeFM1l`;~iP z)AgiqGxbJ1)5YGl0UAfKFp51v&v=_~vjg7)X{^uVQ8w?w_mrh;hv2sC5Y{-=qUp0I zG1h|bfnsxy+DuU~+6HuvwgF8Sn^2YK`E(9?FvD@qi|-8ddW{q1Vx7ndI8WReNgMjElh zxD|Xx<5$6cdj{tn(QgGlzj0lvI@x>L-Jw3KfzNjGs)iwt8OdYCXd}<93GkQ0?=R1p z3AuT*;R*Ww=eqpfDn_||@jSn;gx~sn)rI@?{yxZ8Rq)k^@RdsPl~HenujUWqs~6#` zgSn+XU!fMsSH&T|a!`9emdkajTc*2Xx-<>sF?G{6daj1`*#x(GpVM}uZE2qR(fVMI z!CM-%p5J3$^4RnJ3Zt@a4|&X6b81xt9_w>e<2!cd0fYaqwJ+T7l~O`Om-L<@z2AIE z<>4s=h5ZW=-Q3u9!^y+fa=$#!kQ8zgN&_8uLry>`-x>RWzQ|TQ3g~;^?_f@GJFORk1s%f<4QfD%pDqj`Wgv@he*Kg8o)^5>kRoAMv zDIY|#MM(5HckFsv-5tBWm@W!qK+?sbHNUD>BYy81t~cbyRwz5B8XFxjDGf zlCqM!S26|u+_QO^>C-cqdY&8&lW9h2Z_#rG-6%zjVvNeFNKhmyZBk~#5%U^e`aFiu z;Y!1o@DS0xFmS+EG|D39ufxFESs|j$=xA=(g)iZwmOnv7KaF72k}^6@4zCR5>3Gp; zN^m{Wa|5^GaVvBh>dI>~@4! zC6&VKTY!El*C+Rb;jZs4*hO-E9|zS(_0mH1(Pz;`+*GFJbJ#8RZHBz>Ln+uFH(_8^ z?i0a=zd}K7ciO)Yb`Gq`AJUgG)^uJ(mYJP3-8YOYy$2%8j4@R_B>KZ0? zGNi0!s-ctNh?Z$lrd?DAjl$BrrrFrO*#OFI_H_lQR`ASWvjAa&6T;W!PG@*6qgMg<-~Jho%wSS6Q^WeC3KY7apBv zgi+daB|$vMVjrw&&~Y$hgvVxBhjJP=+J8z50WUAszEPe6LA5Nu z`zplV*!&sA-56E8pjbD3nf=qwF_;da?yw+=#WMQ@WJDY2EdGuA`i?^?zD~En%lcwG z2*CXP{O%c7(C4lj-1_-DgUZwI4k|x47w4l6r@fczV7d-f!ygaE35q$5iB76%j?k&_ zcAzf&B9Stk0g@x%ndOq=PW;dhEcDYTH})r+xh;x2V%f{D6r;?k{5*?L4=q?rzpOxO zq+ix}11OZTh%LqHQsK)9bPoSQKiTHS{&k1w|3alXJt-CfP`R0aD7kV1bLEw za3E+22W}^E15I*8L3Wd{9sKc!fvP759hW!5f!i~%+aw>vTIJuKiFI&&vkA-%V@G{H z*zOwG$$%=z{4DS_A9m}54gA}sSO){17hxxZDtSKvp72n_ov?FYKlzuA(?aWT;MNbj z4bsujxA5~;f$_-amG6h@3kO;oVK>~ggK(hr9_)hKPd@vvup!?U?fW3;yx5c$Ixl$E zjA3)ejl{F2&-P7ch#+U&ooEv*0iHFAJo-)LS<uaACa4y=hrgHj>qA!o0&c&EQs=i3{XnICw z#y1-uh1_*CFi12oNHj1=*_x=rrza)A1N9NmlL7qXkA$9#2R(5H&NlQ5Kb)Qv!7ljMzq}nzPws);Fi`3& zim?)Q{}Oawd9xH7!8GA7u#+i Every subsequent command shown in this document should be run in MinGW shell. Note that in MinGW the `C:\` directory is located in `/c/` > **Important note for Windows users:** It's recommended to do the compilation in the C:\ directory directly as the compilation might fail if the path to the object files is too long (`CreateProcess` has a limit of 32k characters). Moreover, be extra careful with symbolic links present in the project. +## Step 0 - Install the necessary files + +You need to install the headers and library from Cube.AI into the project. + +Inside stm32cubeai directory, run: + +```bash +mkdir -p AI/{Inc,Lib} +mkdir data +``` + +Then copy (or symlink) the files from Cube.AI to the AI directory: + +```bash +# If X-CUBE-AI has been installed from STM32Cube +cp ~/STM32Cube/Repository/Packs/STMicroelectronics/X-CUBE-AI/4.1.0/Middlewares/ST/AI/Inc/* ./AI/Inc/ +cp ~/STM32Cube/Repository/Packs/STMicroelectronics/X-CUBE-AI/4.1.0/Middlewares/ST/AI/lib/ABI2.1/STM32H7/NetworkRuntime410_CM7_IAR.a ./AI/Lib/NetworkRuntime410_CM7_GCC.a + +# If X-CUBE-AI has been downloaded from ST website +cp /Middlewares/ST/AI/Inc/* ./AI/Inc/ +cp /Middlewares/ST/AI/lib/ABI2.1/STM32H7/NetworkRuntime410_CM7_IAR.a ./NetworkRuntime410_CM7_GCC.a +``` + +> Note: On Windows, STM32Cube is usually installed in `C:\Users\name\`, on Linux it's in the `home` directory + ## Step 1 - Generate the code for the network ### Code generation