記事ディレクトリ
概要
STM32 CUBE MX 拡張パッケージ: X-CUBE-AI 導入プロセス:モデル変換、CUBEAI モデル検証、CUBEAI モデル適用。
深層学習アーキテクチャは、複数の LSTM と完全に接続された層 (ドロップアウトおよび活性化関数層を含む) を含む Pytorch モデルを使用します。
バージョン:
STM32CUBEMX: 6.8.1
X-CUBE-AI: 8.1.0 (このバージョンが推奨され、LSTM サポートが更新されています)
ONNX: 1.14.0
参考文献
エラーやバグが発生した場合は、ST コミュニティにアクセスして質問できます: STコミュニティ
CUBEAI スタート ガイド ダウンロード アドレス: X-CUBE-AI スタート ガイド マニュアル
公式アプリケーション例:導入例
STM32CUBEAIのインストール
CUBEAI 拡張機能パッケージのインストールに関するチュートリアルはすでに多数あるため、ここでは詳しく説明しません。CUBEAI のインストール
STM32CUBEMX に CUBEAI をインストールする場合、CUBEAI の最新バージョンがインストールされていない可能性があることに注意してください。そのため、ST 公式 Web サイトにアクセスして最新バージョンをダウンロードできます (最新バージョンはモデルの実装を更新します)。https://www.st.com/zh/embedded-software/x-cube-ai.html
CUBEAIモデルのサポート
現在、CUBEAI は 3 種類のモデルをサポートしています。
- 大声:.h5
- TensorFlow:.tflite
- ONNX 形式に変換できるすべてのモデル: .onnx
CUBEAI をデプロイする Pytorch は、Pytorch で生成されたモデル .pth を .onnx に変換する必要があります。
LSTM モデル変換の考慮事項
- CUBEAI 拡張パッケージと LSTM 変換の ONNX の制限により、Pytorch モデルを構築するときは、LSTM を設定する必要があります
batch_first=False
(モデルのトレーニングとアプリケーションには影響しません)。設定後は、形式に注意する必要があります。入力データと出力データの。 - LSTM モデル内の全結合層を入力する前に、データをスライスし、最後の時間ステップを実行して、いくつかの問題を回避します。
- 複数の LSTM の場合、関数は
forward
複数の入力の形式を取ることができx
、それぞれがx
LSTM の入力になります。
モデル変換
-
Pytorch->Onnx は
、変数を動的に設定できる torch.onnx.export() 関数を使用します。関数の使用方法については多くのチュートリアルがあるため、ここでは繰り返しません。PytorchからONNXへの移行と検証デプロイ後の
モデル適用段階に属するため、入力データは自身で設定できbatch=1
、動的パラメータも設定可能です(動的パラメータとして設定後、CUBEMXで検証したサンプルデータ内)。seq_length
input_num
seq_length
seq_length=1
-
Onnx->STM32の一般的なプロセスは
次のとおりです。STM32 モデルの検証
STM32CUBEMX で対応するモデルを選択すると、その後のネットワーク展開を容易にするためにモデル名を変更できます (デフォルトのネットワーク名は使用しないでください)。
検証フェーズではさまざまな問題が発生する可能性があります。エラーの種類については、以下を参照してください。
モデルアプリケーション
これまでのところ、Pytorch モデルは ONNX に正常に変換され、検証されて CUBEMX に渡されています。以下は STM32 のモデル アプリケーション部分です。
keil でプロジェクトを開いた後、次のディレクトリにモデル関連ファイルを保存します。使用される主な関数は次のとおりです。 (modelName.c、modelName.h
ここで、modelName
は CUBEMX で定義されたモデル名)。
主に使用する機能は以下の通りです。
ai_modelName_create_and_init
: モデルの作成と初期化用ai_modelName_inputs_get
: モデル入力データを取得するために使用されますai_modelName_outputs_get
: モデル出力データを取得するために使用されますai_pytorch_ftc_lstm_run
: モデルをフィードフォワード実行して出力を取得するために使用されます。ai_mnetwork_get_error
: デバッグのためにモデルのエラー コードを取得するために使用されます。
各機能の関連パラメータと使用方法は以下のとおりです。同様のコードは、X-CUBE-AI スタート マニュアル
にあります。
1 エラーの種類とコード
/*!
* @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_API_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_INVALID_SIZE = 0x16,
AI_ERROR_INVALID_VALUE = 0x17,
AI_ERROR_INIT_FAILED = 0x30,
AI_ERROR_ALLOCATION_FAILED = 0x31,
AI_ERROR_DEALLOCATION_FAILED = 0x32,
AI_ERROR_CREATE_FAILED = 0x33,
} 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_IN_USE = 0x0040,
AI_ERROR_CODE_LOCK = 0x0041,
} ai_error_code;
2 モデルの作成と初期化
/*!
* @brief Create and initialize a neural network (helper function)
* @ingroup pytorch_ftc_lstm
* @details Helper function to instantiate and to initialize a network. It returns an object to handle it;
* @param network an opaque handle to the network context
* @param activations array of addresses of the activations buffers
* @param weights array of addresses of the weights buffers
* @return an error code reporting the status of the API on exit
*/
AI_API_ENTRY
ai_error ai_modelName_create_and_init(
ai_handle* network, const ai_handle activations[], const ai_handle weights[]);
入力パラメータnetwork
とactivations
:datatypesai_handle
に注目してくださいvoid*
。初期化方法は以下の通りです。
ai_error err;
ai_handle network = AI_HANDLE_NULL;
const ai_handle act_addr[] = {
activations };
// 实例化神经网络
err = ai_modelName_create_and_init(&network, act_addr, NULL);
if (err.type != AI_ERROR_NONE)
{
printf("E: AI error - type=%d code=%d\r\n", err.type, err.code);
}
3 入力および出力データ変数を取得する
/*!
* @brief Get network inputs array pointer as a ai_buffer array pointer.
* @ingroup pytorch_ftc_lstm
* @param network an opaque handle to the network context
* @param n_buffer optional parameter to return the number of outputs
* @return a ai_buffer pointer to the inputs arrays
*/
AI_API_ENTRY
ai_buffer* ai_modelName_inputs_get(
ai_handle network, ai_u16 *n_buffer);
/*!
* @brief Get network outputs array pointer as a ai_buffer array pointer.
* @ingroup pytorch_ftc_lstm
* @param network an opaque handle to the network context
* @param n_buffer optional parameter to return the number of outputs
* @return a ai_buffer pointer to the outputs arrays
*/
AI_API_ENTRY
ai_buffer* ai_modelName_outputs_get(
ai_handle network, ai_u16 *n_buffer);
最初に入力データと出力データを作成する必要があります。
// 输入输出结构体
ai_buffer* ai_input;
ai_buffer* ai_output;
// 结构体内容如下
/*!
* @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_handle data; /*!< pointer to buffer data */
ai_buffer_meta_info* meta_info; /*!< pointer to buffer metadata info */
/* New 7.1 fields */
ai_flags flags; /*!< shape optional flags */
ai_size size; /*!< number of elements of the buffer (including optional padding) */
ai_buffer_shape shape; /*!< n-dimensional shape info */
} ai_buffer;
次に、関数を呼び出して構造体を割り当てます。
ai_input = ai_modelName_inputs_get(network, NULL);
ai_output = ai_modelName_outputs_get(network, NULL);
次に、構造体のデータに値を割り当てる必要があります。ai_input と ai_output はどちらも入力アドレスと出力アドレスです。複数の入力を持つモデルの場合、配列内の複数の入力にインデックスを付けることができます。
// 单输入
ai_float *pIn;
ai_output[0].data = AI_HANDLE_PTR(pIn);
// 多输入
ai_float *pIn[]
for(int i=0; i<AI_MODELNAME_IN_NUM; i++)
{
ai_input[i].data = AI_HANDLE_PTR(pIn[i]);
}
// 输出
ai_float *pOut;
ai_output[0].data = AI_HANDLE_PTR(pOut);
pIn
これはポインタの配列であり、複数の入力データ ポインタが配列に格納され、AI_MODELNAME_IN_NUM
入力データの量を示すマクロ定義です。
AI_HANDLE_PTR
これはai_handle
型マクロ定義であり、ai_float *
ポインターを渡し、データをai_handle
型に変換します。
#define AI_HANDLE_PTR(ptr_) ((ai_handle)(ptr_))
4 モデルのフィードフォワード出力を取得します
/*!
* @brief Run the network and return the output
* @ingroup pytorch_ftc_lstm
*
* @details Runs the network on the inputs and returns the corresponding output.
* The size of the input and output buffers is stored in this
* header generated by the code generation tool. See AI_PYTORCH_FTC_LSTM_*
* defines into file @ref pytorch_ftc_lstm.h for all network sizes defines
*
* @param network an opaque handle to the network context
* @param[in] input buffer with the input data
* @param[out] output buffer with the output data
* @return the number of input batches processed (default 1) or <= 0 if it fails
* in case of error the error type could be queried by
* using @ref ai_pytorch_ftc_lstm_get_error
*/
AI_API_ENTRY
ai_i32 ai_modelName_run(
ai_handle network, const ai_buffer* input, ai_buffer* output);
この関数は、ネットワーク ハンドル、入力および出力バッファー ポインターを渡し、処理されたバッチの数を返します (アプリケーション ステージは 1 である必要があります)。戻り値が 1 であるかどうかで、モデルが正常に実行されたかどうかを判断できます。
printf("---------Running Network-------- \r\n");
batch = ai_modelName_run(network, ai_input, ai_output);
printf("---------Running End-------- \r\n");
if (batch != BATCH) {
err = ai_mnetwork_get_error(network);
printf("E: AI error - type=%d code=%d\r\n", err.type, err.code);
Error_Handler();
}
実行後、pOut
配列データを表示することでモデルの出力を取得できます。
void printData_(ai_float *pOut, ai_i8 num)
{
printf("(Total Num: %d): ", num);
for (int i=0; i < num; i++)
{
if (i == num-1)
{
printf("%.4f. \r\n", pOut[i]);
}
else
{
printf("%.4f, ", pOut[i]);
}
}
}
モデル適用の概要
公式の展開例の方法に従ってパッケージ化できますAI_Init
。AI_Run
まとめ
発生したバグは継続的に更新されます。