文章目錄
- 友情提示
-
- NCNN簡介
- NCNN注意事項
- **NCNN使用心得**
-
- 小技巧
- 小想法
友情提示
友情提示不針對第三方,為了給讀者更好的體驗
- 建議去我的部落格園進行閱讀
- 微信位址
- GitHub位址
- 歡迎大家關注我的微信公衆号
NCNN簡介
ncnn 是一個為手機端極緻優化的高性能神經網絡前向計算架構。ncnn 從設計之初深刻考慮手機端的部署和使用。無第三方依賴,跨平台,手機端 cpu 的速度快于目前所有已知的開源架構。基于 ncnn,開發者能夠将深度學習算法輕松移植到手機端高效執行,開發出人工智能 APP,将 AI 帶到你的指尖。ncnn 目前已在騰訊多款應用中使用,如 QQ,Qzone,微信,天天P圖等。
關于安裝、編譯、使用步驟等不在贅述,官網有很詳細文檔
Windows | Linux | MacOS | Android | iOS | |
---|---|---|---|---|---|
intel-cpu | ✔️ | ✔️ | ✔️ | ❔ | / |
intel-gpu | ✔️ | ✔️ | ❔ | ❔ | / |
amd-cpu | ✔️ | ✔️ | ✔️ | ❔ | / |
amd-gpu | ✔️ | ✔️ | ❔ | ❔ | / |
nvidia-gpu | ✔️ | ✔️ | ❔ | ❔ | / |
qcom-cpu | ❔ | ✔️ | / | ✅ | / |
qcom-gpu | ❔ | ✔️ | / | ✔️ | / |
arm-cpu | ❔ | ❔ | / | ✅ | / |
arm-gpu | ❔ | ❔ | / | ✔️ | / |
apple-cpu | / | / | / | / | ✅ |
apple-gpu | / | / | / | / | ✔️ |
NCNN注意事項
其實ncnn已經是一個完整的庫,很少有人去改源碼,當然如果你項目特别需要使可以的。
使用出現問題主要是輸入和輸出的地方不對應,以下是本人使用出現的問題。
- 網絡問題一
使用caffe模型的時候,input部分一定要寫成規範格式:
input: "data"
layer {
name: "data"
type: "Input"
top: "data"
input_param { shape: { dim: 1 dim: 1 dim: 256 dim: 512 } }
}
千萬别圖省事寫成如下格式,caffe可以運作沒問題,但是轉化無法識别,這個ncnn資料結構導緻!!!
input: "data"
input_dim: 1
input_dim: 1
input_dim: 256
input_dim: 512
- 網絡問題二
網絡定義的層千萬别出現重複情況,一定要規範定義:
layer {
name: "AAAA"
type: "Concat"
bottom: "box_softmax"
bottom: "conv6_2"
top: "concat_out1"
concat_param {
axis: 2
}
}
layer {
name: "BBBB"
type: "Concat"
bottom: "box_softmax"
bottom: "concat_out1"
top: "concat_out2"
concat_param {
axis: 2
}
}
千萬别寫成如下網絡,在caffe可以穩定運作,但是ncnn會讀取上第一次出現的top層!!!
第一層輸出是
concat_out1
,第二層輸出也是
concat_out1
,當使用
ncnn.extract
會出現錯誤!!!
layer {
name: "AAAA"
type: "Concat"
bottom: "box_softmax"
bottom: "conv6_2"
top: "concat_out1"
concat_param {
axis: 2
}
}
layer {
name: "BBBB"
type: "Concat"
bottom: "box_softmax"
bottom: "concat_out1"
top: "concat_out1"
concat_param {
axis: 2
}
}
- NCNN網絡問題三
這貌似是算作
caffe
的問題,在筆者使用的過程忽略了這一點,幹脆算
NCNN
操作裡面了。
Batch Normalization
層有個
use_global_stats
參數,這個操作的作用是:是否使用caffe内部的均值和方差
換句話的意思就是:
---------
true
:使用caffe内部的均值和方差,其中方差和均值都是固定的,模型訓練好之後,這兩個值就固定了。
---------
false
:使用目前層計算的方差和均值,這個是不固定的,是在訓練過程一直改變,訓練好的時候達到最優。
其中
NCNN
預設使用
true
狀态,不管是
false
還是
true
,最終都是算作
true
caffe
測試的時候得手動設定為
true
- NCNN輸入資料一
正常來說
ncnn
和
caffe
原版的誤差範圍在
0.001
左右,我的資料在
0.000X
範圍徘徊,如果你的資料精确不到第三個有效數字,那就得檢查網絡輸入精度了。
輸入的
substract_mean_normalize
得盡量精确,尤其是歸一化的值!!!
假設
0-255
的圖像需要歸一化到
0-1
:
const float noml_vals[1] = { 0.0078431372549019607843137254902f };
千萬不要寫成下面這樣,讀者可以自己測試,精度差别較大。
const float noml_vals[1] = { 0.0078 }
- NCNN輸入資料二
這裡沒有錯誤點,隻有心得點。
- 如果輸入的是opencv的Mat對象,那隻能是CV_8U類型,别想着去使用CV_32F等其他類型,對結果沒有影響的。
- 關于使用opencv的處理圖像和ncnn的處理圖像效果一樣,比如opencv的resize、normalize、cvtcolor等函數,和ncnn的from_pixels_resize、substract_mean_normalize效果基本沒有差別,本人已經測試。
NCNN使用心得
小技巧
- 輸出為多層
看了NCNN的官網給的例子,它是将輸出轉化為一行資料,然後一個一個的進行處理:
ncnn::Mat out_flatterned = out.reshape(out.w * out.h * out.c);
std::vector<float> scores;
scores.resize(out_flatterned.w);
for (int j=0; j<out_flatterned.w; j++)
{
scores[j] = out_flatterned[j];
}
個人感覺使用這種處理小資料還是可以的,本人使用網絡輸出100 × 100 × 10,這種情況該如何處理?
- 你可以使用那種方法去一個一個儲存到數組,就是浪費點時間。
- 當你需要處理結果的時候呢?比如簡單說去找每個channels的最大值,且主要知道坐标?
本人使用處理如下:
for (size_t i = 0; i < out.c; i++)
{
cv::Mat cv_mat = cv::Mat::zeros(cv::Size(100, 100), CV_8UC1);
ncnn::Mat ppp = out.channel(i);
//轉化為opencv的Mat進行操作,因為有很多矩陣運算就很友善
ppp.to_pixels(cv_mat.data, ncnn::Mat::PIXEL_GRAY);
double max_c = 0, min_c = 0;
cv::Point min_loc, max_loc;
cv::minMaxLoc(cv_mat, &min_c, &max_c, &min_loc, &max_loc);
/*---------------後續操作-----------------*/
}
小想法
NCNN官網有個人問能不能輸入和輸出多個通道資料,後者已經在上文實作,以下看前者。
- NCNN的輸入為
,其中Extractor.input(const char* blob_name, const Mat& in)
是in
ncnn::Mat
類型資料,顯然是
可以多個channels輸入的。
- 可以使用ncnn建立
資料,然後對每個channel通過from_pixel進行指派操作即可。100×100×10
沒有經過具體實作,官網也沒說明,不清楚能不能行,讀者可以根據以上自己嘗試。