寫在前面
我會盡可能地將一些關(guān)鍵概念進行描述和解釋弟塞,但基于 深度學(xué)習(xí) 和 程序設(shè)計 的天坑,固然無法讓一個完全沒有相關(guān)概念基礎(chǔ)的人完全跟上文章的節(jié)奏拙已。對此請看不懂的各位多多見諒咯决记,畢竟這不是一片基礎(chǔ)教程(當(dāng)然,有問題可以在評論區(qū)提出倍踪,我會一一答復(fù))系宫。
參考閱讀適宜人群:
1 關(guān)注AI實現(xiàn)技術(shù)的人們
2 對數(shù)據(jù)結(jié)構(gòu)癡迷的人們
3 MNN的使用者
1 MNN
我們知道索昂,如今的AI主要 以深度學(xué)習(xí)神經(jīng)網(wǎng)絡(luò)的方式 進行實踐。神經(jīng)網(wǎng)絡(luò)模型的基本操作有 訓(xùn)練(Train笙瑟,即創(chuàng)造模型)和 推理(Inference楼镐,即使用模型)。神經(jīng)網(wǎng)絡(luò)模型自有它的復(fù)雜性往枷,所以框产,出現(xiàn)了 神經(jīng)網(wǎng)絡(luò)框架 這樣讓我們可以 忽略模型細節(jié) 來 使用 訓(xùn)練、推理 功能的工具错洁。我們熟知的框架比如:Caffe秉宿,TensorFlow,Pytroch屯碴,Mxnet描睦,Ncnn,當(dāng)然导而,還有我們今天的主角之一忱叭, 阿里巴巴的深度神經(jīng)網(wǎng)絡(luò)推理引擎 MNN。
我們會好奇 MNN模型文件(.mnn)的秘密今艺,想知道它組織結(jié)構(gòu)的秘密(這點對 進行模型轉(zhuǎn)換和模型調(diào)試 有至關(guān)重要的意義)韵丑,即:
它是像一個.json文件一樣使用字符串結(jié)構(gòu)化的存儲?
還是像ncnn的.bin文件一樣只是將二進制的數(shù)值直接無隙存儲虚缎?
調(diào)試MNN模型加載過程中我發(fā)現(xiàn)撵彻,.mnn文件的內(nèi)容竟似乎是 莫名其妙地 從一個“不可讀” 的狀態(tài)變?yōu)榱艘粋€“可使用”的狀態(tài),即:
調(diào)試過程中我找不到字符串解析代碼
調(diào)試過程中我也找不到二進制數(shù)據(jù)映射代碼
我看到的只有:
const flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>> *tensorName() const {
return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>> *>(VT_TENSORNAME);
}
--->
template<typename P> P GetPointer(voffset_t field) const {
return const_cast<Table *>(this)->GetPointer<P>(field);
}
--->
template<typename P> P GetPointer(voffset_t field) {
auto field_offset = GetOptionalFieldOffset(field);
auto p = data_ + field_offset;
return field_offset ? reinterpret_cast<P>(p + ReadScalar<uoffset_t>(p))
: nullptr;
}
--->
voffset_t GetOptionalFieldOffset(voffset_t field) const {
auto vtable = GetVTable();
auto vtsize = ReadScalar<voffset_t>(vtable);
return field < vtsize ? ReadScalar<voffset_t>(vtable + field) : 0;
}
呃……試問一下大家看到這些代碼的感受实牡,應(yīng)該不會很興奮吧……
2 FlatBuffers
其實陌僵,無法解讀MNN模型文件的秘密在于:MNN模型文件采用的存儲結(jié)構(gòu)是 FlatBuffers,而FlatBuffer的特點之一即為“ Access to serialized data without parsing/unpacking”创坞,即 沒有解析過程碗短,沒有解包過程。
我們(某一批特定的“我們”)知道题涨,數(shù)據(jù)結(jié)構(gòu)有 基礎(chǔ)數(shù)據(jù)結(jié)構(gòu) 和 結(jié)構(gòu)化數(shù)據(jù)結(jié)構(gòu)豪椿,那么,先在就優(yōu)先了解一下FlatBuffer中常用的基礎(chǔ)數(shù)據(jù)結(jié)構(gòu):
flatbuffers::String
該圖即 字符串“OK”在 內(nèi)存中携栋,又或 文件中 的 存儲字節(jié)排布(左邊低字節(jié),右邊高字節(jié))咳秉。
- 標(biāo)黃的部分說明 字符串的長度婉支,占用4個字節(jié)(圖示存儲模式為 小端模式)。
圖中表示字符串長度為2澜建,即(2 = 0 * 256^3 + 0 * 256^2 + 0 * 256^1 + 2 * 256^0)向挖; - 緊跟著字符串長度的存儲空間即為 字符串的內(nèi)容蝌以,圖中字符串長度為2,所以緊跟其后的2個字節(jié)為該字符串的有效值何之。
flatbuffers::Vector & flatbuffers::Offset
這兩個數(shù)據(jù)結(jié)構(gòu)結(jié)合在一起使用會比較常見:如:flatbuffers::Vector<flatbuffers::Offset<Op>>
通俗地說跟畅,理解其為:一個指向特定數(shù)據(jù)結(jié)構(gòu)的指針的數(shù)組。
類似flatbuffers::String的理解溶推,4字節(jié)的Vector長度描述后徊件,緊跟6個4字節(jié)的指針描述。
flatbuffers::Table
這個結(jié)構(gòu)比較復(fù)雜蒜危,一片文章中的描述也比較清晰虱痕,我就不自己辛苦畫圖了。
文章:Improving Facebook’s performance on Android with FlatBuffers
簡單來說辐赞,一個Table結(jié)構(gòu) 被分為左右兩部分(如圖中黃色部分pivot point for John即為分界線)部翘,左邊表示數(shù)據(jù)信息的偏移,右邊表示數(shù)據(jù)信息响委。我們把圖中黃色位置計做0新思,則:
- 圖中最左側(cè)的 1 指向黃色位置右邊 第一個矩形;
- 圖中左側(cè)的 6 指向黃色位置右邊 第6個矩形赘风;
- 每個矩形我們依然理解為 1字節(jié)(8位) 的數(shù)據(jù)存儲空間
3 MNN 中描述模型的數(shù)據(jù)結(jié)構(gòu)
有了上面的基礎(chǔ)夹囚,我們會好奇flatbuffers的存儲內(nèi)容與數(shù)據(jù)結(jié)構(gòu)的 具體舉例 或者 應(yīng)用場景。所以贝次,我們來初步了解一下MNN的底層模型數(shù)據(jù)結(jié)構(gòu)崔兴。
3.1 MNN 底層模型數(shù)據(jù)結(jié)構(gòu)全家福
從MNN的源碼中把這些內(nèi)容扒出來然后繪圖貌似也沒有讓它能那么得容易閱讀。哈哈蛔翅,那就圈一些重點吧(當(dāng)然圖中的信息比重點多好多喲):
1 圖中中部靠下的Op部分衍生了近100個操作(或說神經(jīng)網(wǎng)絡(luò)層)的flatbuffers::Table結(jié)構(gòu)的定義敲茄,這邊我只象征性地列舉了常見的4個;
2 FlatBuffer數(shù)據(jù)結(jié)構(gòu)是和存儲對應(yīng)的山析,所以我們可以認(rèn)為MNN的設(shè)計者們期望過將整張圖的內(nèi)容放置到一個MNN模型文件中(至少他們預(yù)留了這樣的擴展性)堰燎;
3 當(dāng)然,現(xiàn)階段的大多MNN模型文件并沒有包含上述全部的信息笋轨,詳情見下圖秆剪。
3.2 MNN 底層模型數(shù)據(jù)結(jié)構(gòu)關(guān)鍵成員
這張圖就簡單了很多,這是我經(jīng)過對一些真實MNN模型的調(diào)試爵政,篩出來的模型關(guān)鍵信息相關(guān)的數(shù)據(jù)結(jié)構(gòu)仅讽。說白了:
1 網(wǎng)絡(luò)結(jié)構(gòu)信息:Op與Op的排布順序
2 網(wǎng)絡(luò)操作的參數(shù)信息(權(quán)重等):存儲在具體的Op衍生數(shù)據(jù)結(jié)構(gòu)中(最右邊的部分)
4 預(yù)告
這篇文章真的相當(dāng)干燥!是否很期待一些更實踐一些的內(nèi)容呢钾挟?
后續(xù)我會再擬草一片文章以舉例的方式來詳細地分析 MNN模型文件的存儲結(jié)構(gòu)的關(guān)系(這篇文章即作為一片技術(shù)基礎(chǔ)參照)洁灵,我會拿出證據(jù)告訴大家,MNN真的是遵照 “這種規(guī)則” 來設(shè)計和運作的掺出。所以我們知道了規(guī)則徽千,完全可以按照你的思想去 修改和調(diào)試 MNN源碼 和 MNN模型苫费。
想把這 有些復(fù)雜并夾雜著大量基礎(chǔ)知識 的 知識實踐 用 短篇幅 說清楚真的不是一件容易的事情啊。(還是講課做分享更輕松哈哈双抽,畢竟有即時的聽眾反饋提問)
先看預(yù)告張草圖吧百框,證明我的每篇文章都是很用心地希望創(chuàng)造一些幫助哦~:)