91欧美超碰AV自拍|国产成年人性爱视频免费看|亚洲 日韩 欧美一厂二区入|人人看人人爽人人操aV|丝袜美腿视频一区二区在线看|人人操人人爽人人爱|婷婷五月天超碰|97色色欧美亚州A√|另类A√无码精品一级av|欧美特级日韩特级

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

如何在TensorFlow Lite Micro中添加自定義操作符(1)

恩智浦MCU加油站 ? 來源:恩智浦MCU加油站 ? 2025-12-26 10:34 ? 次閱讀
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

相信大家在部署嵌入式端的AI應(yīng)用時,一定使用過TensorFlow Lite Micro,以下簡稱TFLm。TFLm 是專為微控制器和嵌入式設(shè)備設(shè)計的輕量級機器學(xué)習(xí)推理框架,它通過模塊化的操作符系統(tǒng)來支持各種神經(jīng)網(wǎng)絡(luò)層的計算。也就是說,我們不僅可以使用內(nèi)嵌的算子運算,還可以自己注冊一個新的算子,更加的靈活。本期就將用兩期的文章以 `reshape.cpp` 為例,詳細說明如何在 TensorFlow Lite Micro 中添加一個新的操作符。

操作符注冊不僅是模型推理的基礎(chǔ),更是優(yōu)化性能、減少內(nèi)存占用的關(guān)鍵環(huán)節(jié)。掌握這一機制,開發(fā)者可以更靈活地定制算子,滿足特定硬件和應(yīng)用需求。

在 TFLite Micro 中,每個操作符都需要經(jīng)過以下幾個關(guān)鍵步驟:

1. 內(nèi)核實現(xiàn):定義操作符的具體計算邏輯

2. 參數(shù)解析:從 FlatBuffer 格式中解析操作符參數(shù)

3. 操作符注冊:將操作符注冊到解析器中,使其可被模型調(diào)用

4. 內(nèi)存管理:處理張量的內(nèi)存分配和釋放

操作符實現(xiàn)的核心組件

1. 文件結(jié)構(gòu)說明

添加新操作符需要修改以下幾個關(guān)鍵文件,每個文件都有其特定的作用:

micro/kernels/reshape.cpp #

操作符的核心計算邏輯實現(xiàn)

micro/micro_mutable_op_resolver.h#

可變操作符解析器,用于動態(tài)注冊操作符

core/api/flatbuffer_conversions.h #

FlatBuffer 參數(shù)解析函數(shù)的聲明

core/api/flatbuffer_conversions.cpp #

FlatBuffer 參數(shù)解析函數(shù)的具體實現(xiàn)

micro/all_ops_resolver.cpp #

全局操作符解析器,包含所有支持的操作符

文件作用詳解:

`micro/kernels/` 目錄:

存放所有操作符的具體實現(xiàn),每個操作符一個文件

`micro_mutable_op_resolver.h`:

提供靈活的操作符注冊接口,允許用戶選擇性地添加操作符

`flatbuffer_conversions.*`:

處理模型文件中的參數(shù)解析,將 FlatBuffer 格式轉(zhuǎn)換為 C++ 結(jié)構(gòu)體

`all_ops_resolver.cpp`:

預(yù)定義了所有標準操作符的注冊,適用于需要完整操作符支持的場景

2. 核心實現(xiàn)文件分析

2.1 頭文件引入

文件位置:`micro/kernels/reshape.cpp`

#include
#include"tensorflow/lite/c/builtin_op_data.h"
#include"tensorflow/lite/c/common.h"
#include"tensorflow/lite/kernels/internal/tensor_ctypes.h"
#include"tensorflow/lite/kernels/kernel_util.h"
#include"tensorflow/lite/kernels/op_macros.h"
#include"tensorflow/lite/micro/kernels/kernel_util.h"
#include"tensorflow/lite/micro/memory_helpers.h"
#include"tensorflow/lite/micro/micro_utils.h"

頭文件說明:

`builtin_op_data.h`:包含所有內(nèi)置操作符的參數(shù)結(jié)構(gòu)體定義

`common.h`:TFLite 的基礎(chǔ)數(shù)據(jù)類型和狀態(tài)碼定義

`tensor_ctypes.h`:張量數(shù)據(jù)類型相關(guān)的工具函數(shù)

`kernel_util.h`:操作符實現(xiàn)的通用工具函數(shù)

`op_macros.h`:操作符實現(xiàn)中常用的宏定義

`micro/kernels/kernel_util.h`:Micro 版本特有的內(nèi)核工具函數(shù)

`memory_helpers.h`:內(nèi)存管理相關(guān)的輔助函數(shù)

`micro_utils.h`:Micro 版本的通用工具函數(shù)

2.2 命名空間和常量定義

namespacetflite {
namespaceops {
namespacemicro {
namespacereshape {
constexprintkInputTensor =0;
constexprintkOutputTensor =0;

命名空間說明:

`tflite::reshape`:四層命名空間確保了代碼的組織性和避免命名沖突

常量定義:`kInputTensor` 和 `kOutputTensor` 定義了輸入輸出張量的索引,Reshape 操作只有一個輸入和一個輸出

2.3 核心函數(shù)實現(xiàn)

ReshapeOutput 函數(shù) - 形狀計算邏輯

TfLiteStatus ReshapeOutput(TfLiteContext* context, TfLiteNode* node) {
 MicroContext* micro_context =GetMicroContext(context);
// 獲取輸入和輸出張量 - 使用臨時分配避免持久內(nèi)存占用
 TfLiteTensor* input = micro_context->AllocateTempInputTensor(node, kInputTensor);
 TfLiteTensor* output = micro_context->AllocateTempOutputTensor(node, kOutputTensor);
// 計算輸入元素總數(shù) - 用于驗證 reshape 操作的合法性
intnum_input_elements =NumElements(input);
 TfLiteIntArray* output_shape = output->dims;
// 處理特殊情況:-1 維度自動計算
// TensorFlow 允許一個維度設(shè)為 -1,表示根據(jù)其他維度自動推斷
intnum_output_elements =1;
intstretch_dim = -1;
for(inti =0; i < output_shape->size; ++i) {
 intvalue = output_shape->data[i];
 if(value == -1) {
  TF_LITE_ENSURE_EQ(context, stretch_dim, -1); // 確保只有一個 -1 維度
   stretch_dim = i;
  }else{
   num_output_elements *= value;
  }
 }
// 如果存在 -1 維度,自動計算其大小
if(stretch_dim != -1) {
  TfLiteEvalTensor* output_eval =
    tflite::micro::GetEvalOutput(context, node, kOutputTensor);
 TF_LITE_ENSURE_STATUS(tflite::micro::CreateWritableTensorDimsWithCopy(
    context, output, output_eval));
  output_shape = output->dims; // 更新形狀指針
  output_shape->data[stretch_dim] = num_input_elements / num_output_elements;
  num_output_elements *= output_shape->data[stretch_dim];
 }
// 確保輸入輸出元素數(shù)量一致 - Reshape 不改變元素總數(shù)
TF_LITE_ENSURE_EQ(context, num_input_elements, num_output_elements);
TF_LITE_ENSURE_TYPES_EQ(context, input->type, output->type); // 確保數(shù)據(jù)類型一致
// 釋放臨時張量 - 避免內(nèi)存泄漏
 micro_context->DeallocateTempTfLiteTensor(input);
 micro_context->DeallocateTempTfLiteTensor(output);
returnkTfLiteOk;
}

函數(shù)作用詳解:

臨時張量分配:使用 `AllocateTempInputTensor` 和 `AllocateTempOutputTensor` 獲取張量信息,這些是臨時分配,不會占用持久內(nèi)存

形狀驗證:確保 reshape 操作的合法性,輸入輸出元素總數(shù)必須相等

自動維度推斷:處理 -1 維度的特殊情況,這是 TensorFlow 的標準特性

內(nèi)存管理:及時釋放臨時張量,這在內(nèi)存受限的微控制器環(huán)境中非常重要

Prepare 函數(shù)-操作符準備階段:

TfLiteStatusPrepare(TfLiteContext* context, TfLiteNode* node){
// 驗證輸入輸出數(shù)量 - Reshape 可以有 1 個或 2 個輸入(第二個輸入是可選的形狀參數(shù))
 TF_LITE_ENSURE(context, NumInputs(node) ==1|| NumInputs(node) ==2);
 TF_LITE_ENSURE_EQ(context, NumOutputs(node),1); // 只有一個輸出
// 執(zhí)行輸出形狀重塑 - 在準備階段確定最終的輸出形狀
 TF_LITE_ENSURE_EQ(context, ReshapeOutput(context, node), kTfLiteOk);
returnkTfLiteOk;
}

Prepare函數(shù)說明:

輸入驗證:Reshape 操作支持 1-2 個輸入,第二個輸入是可選的形狀張量

形狀計算:在準備階段就確定輸出形狀,避免在執(zhí)行階段重復(fù)計算

錯誤檢查:使用 `TF_LITE_ENSURE` 宏進行參數(shù)驗證,失敗時會返回錯誤狀態(tài)

Eval 函數(shù)-操作符執(zhí)行階段:

TfLiteStatus Eval(TfLiteContext* context, TfLiteNode* node) {
// 獲取輸入輸出張量 - 使用 EvalTensor 進行實際計算
constTfLiteEvalTensor* input =
   tflite::GetEvalInput(context, node, kInputTensor);
 TfLiteEvalTensor* output =
   tflite::GetEvalOutput(context, node, kOutputTensor);
// 計算輸入數(shù)據(jù)大小 - 需要拷貝的字節(jié)數(shù)
 size_t input_bytes;
 TF_LITE_ENSURE_STATUS(TfLiteTypeSizeOf(input->type, &input_bytes));
 input_bytes *= ElementCount(*input->dims);
// 執(zhí)行數(shù)據(jù)拷貝(如果不是原地操作)
// 原地操作:輸入輸出使用同一塊內(nèi)存,無需拷貝
if(input->data.raw != output->data.raw) {
  memcpy(output->data.raw, input->data.raw, input_bytes);
 }
returnkTfLiteOk;
}

Eval函數(shù)說明:

EvalTensor 使用:在執(zhí)行階段使用 `TfLiteEvalTensor`,它包含實際的數(shù)據(jù)指針

原地操作優(yōu)化:檢查輸入輸出是否共享內(nèi)存,避免不必要的數(shù)據(jù)拷貝

內(nèi)存拷貝:Reshape 操作本質(zhì)上只是改變數(shù)據(jù)的解釋方式,不改變數(shù)據(jù)內(nèi)容

2.4 操作符注冊函數(shù)

TfLiteRegistration_V1 Register_RESHAPE() {
returntflite::micro::RegisterOp(nullptr, reshape::Prepare, reshape::Eval);
}
} // namespace reshape
} // namespace micro
} // namespace ops
} // namespace tflite

注冊函數(shù)說明:

RegisterOp 函數(shù):創(chuàng)建操作符注冊結(jié)構(gòu)體,包含初始化、準備和執(zhí)行函數(shù)指針

nullptr 參數(shù):第一個參數(shù)是初始化函數(shù),Reshape 不需要特殊初始化,所以傳入 nullptr

函數(shù)指針:傳入 Prepare 和 Eval 函數(shù)指針,框架會在適當時機調(diào)用這些函數(shù)

3. 參數(shù)解析實現(xiàn)

3.1 解析函數(shù)聲明

文件位置:`core/api/flatbuffer_conversions.h`

TfLiteStatusParseReshape(constOperator* op, ErrorReporter* error_reporter,
             BuiltinDataAllocator* allocator,voidbuiltin_data);

聲明說明:

Operator* op:來自 FlatBuffer 的操作符定義,包含所有參數(shù)信息

ErrorReporter:用于報告解析過程中的錯誤

BuiltinDataAllocator:專用的內(nèi)存分配器,用于分配參數(shù)結(jié)構(gòu)體

builtin_data:輸出參數(shù),指向解析后的參數(shù)結(jié)構(gòu)體

3.2 解析函數(shù)實現(xiàn)

文件位置:`core/api/flatbuffer_conversions.cpp`

TfLiteStatusParseReshape(constOperator* op,ErrorReporter* error_reporter,
            BuiltinDataAllocator* allocator,
            voidbuiltin_data) ;

解析函數(shù)詳解:

參數(shù)驗證:`CheckParsePointerParams` 確保所有指針參數(shù)有效

安全分配器:`SafeBuiltinDataAllocator` 提供異常安全的內(nèi)存分配

FlatBuffer 解析:從序列化的模型文件中提取 reshape 參數(shù)

格式轉(zhuǎn)換:將 FlatBuffer 格式轉(zhuǎn)換為 TFLite 內(nèi)部使用的 C 結(jié)構(gòu)體格式

所有權(quán)轉(zhuǎn)移:使用 `release()` 將參數(shù)結(jié)構(gòu)體的所有權(quán)轉(zhuǎn)移給框架

3.3 在解析開關(guān)中添加對應(yīng)的case

文件位置:`core/api/flatbuffer_conversions.cpp`

在 `ParseOpData` 函數(shù)的 switch 語句中添加:

caseBuiltinOperator_RESHAPE: {
returnParseReshape(op, error_reporter, allocator, builtin_data);
}

開關(guān)語句說明:

這個 switch 語句是 TFLite 參數(shù)解析的核心分發(fā)機制

根據(jù)操作符類型調(diào)用相應(yīng)的解析函數(shù)

`BuiltinOperator_RESHAPE` 是在FlatBuffer schema中定義的枚舉值

通過本指南,我們深入了解了 TensorFlow Lite Micro 的操作符注冊機制,包括其設(shè)計理念、實現(xiàn)方式以及在嵌入式場景中的重要性。

未來,隨著邊緣計算和微控制器 AI 的快速發(fā)展,理解并運用這些底層機制將成為構(gòu)建高效、可擴展 AI 系統(tǒng)的核心能力。建議讀者在實踐中嘗試自定義算子注冊,并結(jié)合實際項目進行優(yōu)化,以真正發(fā)揮 TensorFlow Lite Micro 的潛力。

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • 微控制器
    +關(guān)注

    關(guān)注

    48

    文章

    8371

    瀏覽量

    164508
  • 嵌入式
    +關(guān)注

    關(guān)注

    5198

    文章

    20435

    瀏覽量

    333907
  • 操作符
    +關(guān)注

    關(guān)注

    0

    文章

    23

    瀏覽量

    9268
  • tensorflow
    +關(guān)注

    關(guān)注

    13

    文章

    334

    瀏覽量

    62164

原文標題:TensorFlow Lite Micro玩法升級!

文章出處:【微信號:NXP_SMART_HARDWARE,微信公眾號:恩智浦MCU加油站】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。

收藏 人收藏
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

    評論

    相關(guān)推薦
    熱點推薦

    Linux命令“!”操作符的用法

    Linux的'!'符號或操作符可以用作邏輯否定運算,也可以用于在歷史記錄獲取命令并進行修改或運行以前執(zhí)行過的命令。
    發(fā)表于 07-05 10:07 ?2249次閱讀

    何在e203 SOC添加自定義外設(shè)

    何在E203 添加自定義的外設(shè),困擾已久,以下是一個從別處借鑒而來的方法: 1、設(shè)計好自定義
    發(fā)表于 10-20 10:38

    何在android設(shè)備上安裝自定義rom

    完成后,請執(zhí)行相同的操作,但不要選擇自定義rom,而是選擇間隙。安裝間隙之前需要使用一些自定義rom,您可以從自定義rom的開發(fā)人員網(wǎng)頁上了解,如果他們沒有提及任何相關(guān)內(nèi)容,只需在
    的頭像 發(fā)表于 11-05 10:48 ?6160次閱讀

    C++之操作重載學(xué)習(xí)的總結(jié)(二)

    復(fù)數(shù)的概念可以通過自定義類實現(xiàn);復(fù)數(shù)的運算操作可以通過操作符重載實現(xiàn);賦值操作符只能通過成員函數(shù)實現(xiàn);
    的頭像 發(fā)表于 12-24 16:26 ?1077次閱讀

    C++之操作符重載學(xué)習(xí)的總結(jié)

    操作符重載是c++的強大特性之一;操作符重載的本質(zhì)是通過函數(shù)擴展操作符的功能;operator 關(guān)鍵字是實現(xiàn)操作符重載的關(guān)鍵。
    的頭像 發(fā)表于 12-24 16:36 ?1190次閱讀

    何在LabVIEW實現(xiàn)自定義控件

    本文檔的主要內(nèi)容詳細介紹的是如何在LabVIEW實現(xiàn)自定義控件。
    發(fā)表于 01-14 17:17 ?50次下載
    如<b class='flag-5'>何在</b>LabVIEW<b class='flag-5'>中</b>實現(xiàn)<b class='flag-5'>自定義</b>控件

    何在TensorFlow2里使用Keras API創(chuàng)建一個自定義CNN網(wǎng)絡(luò)?

    概述 本示例工程我們會在 TensorFlow2 下使用 Keras API 創(chuàng)建一個自定義 CNN 網(wǎng)絡(luò),在 Vitis-AI 1.3 環(huán)境下編譯成 Xilinx DPU 上運行的模型文件,并在
    的頭像 發(fā)表于 04-15 11:36 ?2814次閱讀

    自定義視圖組件教程案例

    自定義組件 1.自定義組件-particles(粒子效果) 2.自定義組件- pulse(脈沖button效果) 3.自定義組件-progr
    發(fā)表于 04-08 10:48 ?15次下載

    教程 2:添加特征-自定義配置文件創(chuàng)建

    教程 2:添加特征 - 自定義配置文件創(chuàng)建
    發(fā)表于 03-15 19:39 ?0次下載
    教程 2:<b class='flag-5'>添加</b>特征-<b class='flag-5'>自定義</b>配置文件創(chuàng)建

    自定義AXI-Lite接口的IP及源碼分析

    在 Vivado 自定義 AXI4-Lite 接口的 IP,實現(xiàn)一個簡單的 LED 控制功能,并將其掛載到 AXI Interconnect 總線互聯(lián)結(jié)構(gòu)上,通過 ZYNQ 主機控制,后面對 Xilinx 提供的整個 AXI4
    發(fā)表于 06-25 16:31 ?5046次閱讀
    <b class='flag-5'>自定義</b>AXI-<b class='flag-5'>Lite</b>接口的IP及源碼分析

    教程 2:添加特征-自定義配置文件創(chuàng)建

    教程 2:添加特征 - 自定義配置文件創(chuàng)建
    發(fā)表于 07-06 18:50 ?0次下載
    教程 2:<b class='flag-5'>添加</b>特征-<b class='flag-5'>自定義</b>配置文件創(chuàng)建

    添加自定義屬性控制fridaserver啟動和停止

    添加自定義屬性控制fridaserver啟動和停止
    的頭像 發(fā)表于 08-09 10:08 ?2916次閱讀
    <b class='flag-5'>添加</b><b class='flag-5'>自定義</b>屬性控制fridaserver啟動和停止

    何在Matlab自定義Message

    自定義Message 當我們的 message 消息比較復(fù)雜時,通常要用到自定義的 message 消息,MATLAB 2020b以上的版本自帶了ROS Toolbox Interface
    的頭像 發(fā)表于 11-15 18:12 ?2612次閱讀
    如<b class='flag-5'>何在</b>Matlab<b class='flag-5'>中</b><b class='flag-5'>自定義</b>Message

    “+”操作符的使用技巧

    這篇寫個平時易被忽略的小知識點,一元 + 操作符的使用技巧。
    的頭像 發(fā)表于 12-28 13:27 ?1478次閱讀

    何在TensorFlow Lite Micro添加自定義操作符(2)

    reshape算子進行說明,如何將reshape算子注冊到解析器,接下來介紹如果我們想自定義一個算子需要干些什么。
    的頭像 發(fā)表于 12-26 10:53 ?1106次閱讀