1 概述
文章:Mnn Converter Debug
上述文章中分歇,我們介紹了Mnn Converter Debug 工程的構(gòu)建辦法俗他,構(gòu)建了該工程,我們可以更便捷地通過調(diào)試快速理解 Mnn Converter 的架構(gòu) 與 流程,并進行簡單的調(diào)試修改蛔钙。
但當我們轉(zhuǎn)化的模型越來越多,越來越復(fù)雜荠医。我們會發(fā)現(xiàn):
1)不同模型的轉(zhuǎn)換過程可能遇到相似的問題
2)轉(zhuǎn)換文件的代碼復(fù)雜度變得愈發(fā)復(fù)雜
3)復(fù)雜的定制化轉(zhuǎn)換變得異常困難甚至無法進行
4)模型更新時吁脱,再次轉(zhuǎn)換甚至找不到原始的模型轉(zhuǎn)換代碼
我們需要 對我們實現(xiàn)的 定制化模型轉(zhuǎn)換進行必要的管理
所以該篇文章桑涎,
1)我會以 onnx-->mnn 的轉(zhuǎn)換需求為例,對 MnnConvertDebug 添加微架構(gòu)設(shè)計兼贡。
2)簡單介紹基于該架構(gòu)的 定制化模型轉(zhuǎn)換實現(xiàn)辦法
3)簡單介紹定制化模型轉(zhuǎn)換過程中的常見問題
2 MnnConverterDebug 微架構(gòu)設(shè)計
2.1 基本架構(gòu)
2.2 模塊說明
2.2.1 JsonDump
Mnn模型 基于 FlatBuffers 結(jié)構(gòu)存儲攻冷,難以直接閱讀。
有關(guān) Mnn FlatBuffers 的相關(guān)介紹可以參考:
文章:FlatBuffers遍希,MNN模型存儲結(jié)構(gòu)基礎(chǔ) ---- 無法解讀MNN模型文件的秘密
文章:做個游戲吧等曼?玩兒轉(zhuǎn)Mnn模型存儲結(jié)構(gòu)
所以, Mnn 提供了 JsonDump工具凿蒜, 可以藉由 Mnn 模型導(dǎo)出 Mnn 基于json描述的網(wǎng)絡(luò)結(jié)構(gòu)禁谦。我們 將這個工具集入框架,在完成Mnn模型轉(zhuǎn)換的同時废封,通過JsonDump將Mnn的網(wǎng)絡(luò)結(jié)構(gòu)Dump出來州泊,方便對模型進行分析。
2.2.2 Template
約定的 “死”的框架漂洋,即可抽離 “活”的定制化
我們將框架相關(guān)的模板文件放置在此模塊遥皂,避免定制化文件中存在大量的重復(fù)代碼,降低維護代價刽漂。
2.2.3 Tools
模型轉(zhuǎn)換的通用工具支持演训,包括:
1)插入、鏈接 Mnn 操作節(jié)點
2)生成 Mnn 操作節(jié)點
3)轉(zhuǎn)換 Mnn 操作節(jié)點
4)未實現(xiàn)的 Mnn 節(jié)點轉(zhuǎn)換器
2.2.4 Converters
這邊將一個 特定模型(一個網(wǎng)絡(luò))的轉(zhuǎn)換工具 定義為一個轉(zhuǎn)換器(Converter)贝咙。
當然样悟,相似的模型可能復(fù)用同一個轉(zhuǎn)換器。
比如大多數(shù)簡單模型可以直接使用Mnn提供的轉(zhuǎn)換器颈畸。(不使用我們定制化的)
2.2.3 ConverterRed
非定制化代碼乌奇,即MnnConverterDebug構(gòu)建時必要的代碼依賴,參考:
文章:Mnn Converter Debug
2.2.6 Main
主流程控制器眯娱,主要配置包括:
- 轉(zhuǎn)換器 的選擇
- onnx模型文件 路徑配置
- 目標mnn模型文件 路徑配置
- mnn json dump(不含權(quán)重)文件 路徑配置
- mnn json dump(含權(quán)重信息)文件 路徑配置
2.3 轉(zhuǎn)換流程
注:圖中的【MnnDebug】【ModelManager】【Python】該篇文章暫不進行具體的說明礁苗。
框架執(zhí)行流程:
1)首先,選擇一個 onnx模型 作為輸入徙缴;
2)基于模板創(chuàng)建一個 轉(zhuǎn)換器(比如ConverterY)進行模型調(diào)試试伙,轉(zhuǎn)換出 mnn 模型;
3)對轉(zhuǎn)換好的 Mnn 模型進行 json dump于样;
4)測試模型效果(比如構(gòu)建一個MnnDebug工程疏叨,或使用其他辦法);
5)Run onnx 或者 更原始的模型(比如pytorch穿剖、mxnet等)蚤蔓,設(shè)置與MnnDebug相同的輸入( 比如全部值設(shè)置為1.1),比對輸出糊余,保證一致秀又。
2.4 Demo
工程Demo Git鏈接
構(gòu)建與集成說明:Mnn Converter Debug
3 使用 & 調(diào)試
3.1 新轉(zhuǎn)換器 的構(gòu)建 & 配置
1)于 MnnConverterDebug/Custom/Converters 中建立 新的轉(zhuǎn)換器文件(.hpp/.cpp)
2)基于 MnnConverterDebug /Custom/Template/CYCustomConverter_Template.hpp/.cpp 填寫 新創(chuàng)建的新轉(zhuǎn)換器
3)在 main.mm 中引入 新創(chuàng)建的轉(zhuǎn)換器 的 .hpp 文件
4)在 main.mm 中替換轉(zhuǎn)換函數(shù) onnx2MNNNet(modelPath.modelFile, modelPath.bizCode, netT); 為 新創(chuàng)建的轉(zhuǎn)換函數(shù)单寂。
3.2 調(diào)試步驟(新創(chuàng)建的轉(zhuǎn)換器文件的定制化修改)
我們假設(shè)已經(jīng)完成了3.1接2)的模板代碼拷貝
3.2.1 測試原始轉(zhuǎn)換
將 __BREAK_TAG、__MANUAL_TAG 設(shè)置一個較大的值(如3000吐辙,目前的網(wǎng)絡(luò)幾乎不會有這么多操作)宣决。 此時,轉(zhuǎn)換器沒有任何定制化修改昏苏,完全走 Mnn原始的自動轉(zhuǎn)換邏輯尊沸。
[轉(zhuǎn)換順利]:即給予相同的輸入的情況下,轉(zhuǎn)換的mnn模型 與 轉(zhuǎn)換前模型的輸出完全一致是贤惯,表示模型轉(zhuǎn)換順利洼专,無須定制化調(diào)試修改,流程結(jié)束孵构。
[轉(zhuǎn)換異常]:沒有轉(zhuǎn)換出mnn模型壶熏,或者轉(zhuǎn)換出的mnn模型輸出異常…… 孩紙浦译!苦逼的時刻到了!做好準備吧溯职!繼續(xù)往下看
3.2.2 查看控制臺輸出
參考控制臺輸出精盅,模板代碼會自動打印所有 onnx模型 的 操作索引、操作名稱谜酒、操作類型叹俏,如圖:
3.3.3 尋找問題操作
參考依據(jù) 控制臺輸出索引,修改 __BREAK_TAG 的值僻族,找到轉(zhuǎn)換開始出現(xiàn)問題的操作粘驰。 出現(xiàn)問題指:轉(zhuǎn)換崩潰、執(zhí)行崩潰述么、執(zhí)行結(jié)果不合期望 等蝌数。
3.3.4 分析問題原因
通過 查看onnx網(wǎng)絡(luò)結(jié)構(gòu)(推薦工具Netron)、分析onnx轉(zhuǎn)換前的模型網(wǎng)絡(luò)結(jié)構(gòu)(比如pytorch度秘、mxnet等)顶伞、又或調(diào)試Mnn源碼 等方法 嘗試 確認問題產(chǎn)生的原因。
3.3.5 嘗試解決問題
確認問題后進行問題修改剑梳,可能需要通過 修改Mnn源碼唆貌、添加新的轉(zhuǎn)換器等、添加新的Mnn
操作垢乙、甚至設(shè)計重寫設(shè)計局部網(wǎng)絡(luò)等方法解決問題锨咙。
3.3.6 保證最終輸出
循環(huán)進行 3.3.3 ~ 3.3.5 直到保證Mnn模型最終輸出與原始模型的一致性。
一致性標準參考:每個輸出對應(yīng)值的小數(shù)點后至少三位完全一致追逮。
4 模型轉(zhuǎn)換常見問題參考
4.1 轉(zhuǎn)換異常
魔性轉(zhuǎn)換過程中酪刀,可能根本無法正常輸出mnn模型文件
解決參考:
1)檢查輸入粹舵、輸出路徑配置
2)參考 [3.2 調(diào)試步驟],找到造成 轉(zhuǎn)換異常 的操作蓖宦,然后針對修改齐婴。
3)分析過程可以適當參考模型的JsonDump結(jié)構(gòu)
常見問題原因:
1)對應(yīng)操作參數(shù)沒有設(shè)置好
2)操作鏈接設(shè)置錯誤
4.2 模型推理異常
模型轉(zhuǎn)換順利,并不代表模型可以被正常使用稠茂。即在模型的加載柠偶、推理過程中出現(xiàn)崩潰。
解決參考:
1)參考 [3.2 調(diào)試步驟]睬关,找到造成 轉(zhuǎn)換異常 的操作诱担,然后針對修改。
2)分析過程可以適當參考模型的JsonDump結(jié)構(gòu)
常見問題原因:
1)操作鏈接設(shè)置錯誤
2)相關(guān)操作輸入輸出不匹配(比如A-B操作相關(guān)电爹,A操作輸入時2維蔫仙,而B操作的輸入期望是4維)
4.3 操作結(jié)果不一致
模型推理順利,同樣不等同于轉(zhuǎn)換成功丐箩。
我們必須保證 轉(zhuǎn)換的mnn模型 在與原始模型 輸入一致的情況下摇邦,輸出結(jié)果與原始模型完全一致。
思路參考:
1)依次對齊對應(yīng)操作的輸出形狀(shape)
2)依次對齊對應(yīng)操作的輸出值(至少要保證三位小數(shù)是完全一致的)
目標參考:
網(wǎng)絡(luò)輸出層數(shù)據(jù)完全符合期望屎勘。
4.4 操作轉(zhuǎn)換不支持
有些操作Mnn有實現(xiàn)施籍,但相關(guān)的轉(zhuǎn)換代碼沒有實現(xiàn),這時候我們需要手動轉(zhuǎn)換對應(yīng)的操作概漱。
解決參考:
1)簡單的操作丑慎,可以直接使用Demo中的CYOpCreater中定義的操作生成方法生成。
2)也可以手動完成對應(yīng)操作的生成代碼
4.4 操作不支持
有些Mnn本身沒有實現(xiàn)瓤摧,而我們使用又比較著急竿裂,此時可以先自行添加對應(yīng)操作的簡易版本。
解決參考:
1)參考Mnn官方文檔照弥,添加新操作
文檔 - Mnn添加操作
2)有些操作可以基于Mnn已存在的操作添加參數(shù)配置邏輯來完成我們的目標
4.5 操作運算異常
Mnn的部分偏門操作還是必可避免的存在一些邏輯bug腻异,造成輸出異常。
解決參考:
1)閱讀操作源碼这揣,理清思路捂掰,修改bug。
2)對于比較確認的bug的非補丁式修改曾沈,建議向mnn提交merge request这嚣,惠及更多的朋友哦~
4.6 網(wǎng)絡(luò)中間結(jié)構(gòu)復(fù)雜
有時候 原始模型(比如pytorch)結(jié)構(gòu)很簡單,但是轉(zhuǎn)換成 中間模型(比如onnx)后塞俱,部分操作變得異常復(fù)雜姐帚,更糟糕的是,后續(xù)轉(zhuǎn)換的問題也處在這些復(fù)雜的操作中障涯。這時候我們或許可以考慮直接 基于原始模型(比如pytorch)的結(jié)構(gòu) 對目標模型(mnn模型)的部分網(wǎng)絡(luò)結(jié)構(gòu)進行重設(shè)計罐旗。代價很大膳汪,但針對老板的一些硬性需求,還是值得一做九秀。
舉例:原始模型操作被onnx復(fù)雜化:
針對 該種場景遗嗽,建議將轉(zhuǎn)換設(shè)計用繪圖的方式繪制出來,因為在調(diào)試過程中會難免會對設(shè)計的結(jié)構(gòu)進行修改鼓蜒。當對應(yīng)的操作比較復(fù)雜時痹换,這些修改完全基于代碼去調(diào)試 幾乎是一個不可能完成的任務(wù)。設(shè)計繪圖關(guān)鍵要素參考如下:
1)擬定操作類型(如:Reshape)
2)擬定操作名稱(如:C0)
3)擬定操作關(guān)鍵參數(shù)
4)計算操作輸出形狀(如1,512,1,119都弹,方便測試比對)
結(jié)語
定制化模型轉(zhuǎn)換是一個大坑娇豫,其中很多具體的填坑場景也是不盡相同的。
該篇文章提供一種基于onnx-->mnn 的調(diào)試框架畅厢。一定程度上可以簡化了模型轉(zhuǎn)換的復(fù)雜度冯痢。
再次附上Demo的參考鏈接:
工程Demo Git鏈接
(基于公司的保密需要,我不方便將具體模型的轉(zhuǎn)換相關(guān)的框架應(yīng)用代碼進行分享參考框杜,只能手寫一些簡單模型浦楣,提供一些簡單場景的示例,大家見諒咯~)
模型轉(zhuǎn)換不是一件容易的事情
模型轉(zhuǎn)換目前還很難成為一個自動化的工作
Mnn的模型定制化轉(zhuǎn)換更加復(fù)雜
基于Mnn本身架構(gòu)的復(fù)雜性(模型的flatbuffers存儲咪辱、模型運算中間結(jié)果數(shù)據(jù)排布的多樣性:NCHW椒振,NC4HW4、Mnn緩存機制的處理梧乘、Mnn并發(fā)操作代碼的閱讀等) ,Mnn的模型轉(zhuǎn)換遇到的問題的解決更加復(fù)雜庐杨。
所以选调,轉(zhuǎn)換Mnn模型,信心灵份、耐心 每樣都必不可少仁堪。
希望該篇文章能為轉(zhuǎn)換模型遇到困難無法繼續(xù)進行的同學(xué)提供一些思路的參考,也歡迎這些朋友將遇到的問題分享出來填渠,我們一起討論弦聂、解決、借鑒氛什。