深度学习-服务端训练+android客户端物体识别实战(caffe入门教程+mobilenet+ncnn+android)
文章目錄
- 背景
-
物體識別簡介
-
自動駕駛
- 淘寶京東使用物體識別技術(shù)
- 公司業(yè)務(wù)需求
-
深度學(xué)習(xí)簡介
-
深度學(xué)習(xí)的位置
- 深度學(xué)習(xí)概念
- 深度學(xué)習(xí)優(yōu)勢
-
深度學(xué)習(xí)基礎(chǔ)知識
-
感知機
- 激活函數(shù)
- 多層感知機
- 卷積神經(jīng)網(wǎng)絡(luò)
-
卷積層 * 池化層
- 模型訓(xùn)練
-
前向傳播 * 反向傳播與參數(shù)優(yōu)化
-
深度學(xué)習(xí)服務(wù)端框架
-
tensorFlow
- keras
- pytorch
- Caffe/Caffe2.0
-
caffe框架
-
為何選擇caffe
- caffe環(huán)境搭建
- caffe基礎(chǔ)
-
數(shù)據(jù)集?模塊概要圖?solver(prototxt) 執(zhí)行者配置?神經(jīng)網(wǎng)絡(luò)可視化?caffe中的基礎(chǔ)概念
-
blobs?layer 神經(jīng)層?net 神經(jīng)網(wǎng)絡(luò) * forward/backward 前向傳播/反向傳播
-
輕量級客戶端框架-ncnn
-
ncnn簡介
- ncnn+caffe+mobilenet實戰(zhàn)
-
ncnn環(huán)境搭建 * 模型轉(zhuǎn)化(caffe格式-> ncnn格式)
- 源碼解析
-
文件目錄?執(zhí)行流程?重點代碼?效果展示?其他工程的效果圖
-
相關(guān)學(xué)習(xí)資料
-
教學(xué)視頻
- 開源項目
- 參考博客
背景
產(chǎn)品以后的發(fā)展需要添加更多科技元素,如下:
- 人臉識別
- 物體識別
- 場景識別
以下以物體識別為重點,使用到了深度學(xué)習(xí)技術(shù),以下我們將逐一展開。
本次分享的重點是深度學(xué)習(xí)+caffe+ncnn,其余部分將簡單的進行帶過。
注:本文主要以有監(jiān)督的學(xué)習(xí)為主(分類和回歸問題),無監(jiān)督學(xué)習(xí)不作為分享范圍。
物體識別簡介
物體識別(俗稱Object detection),是近年來興起的技術(shù),這也是人工智能的首要目標(biāo)之一。這是一種完全模擬人眼識別的技術(shù),即使在物體旋轉(zhuǎn)、變色、部分展示等的情況下,同樣具備優(yōu)秀的識別效果。
人工智能目標(biāo)是:
- 讓機器看世界
- 讓機器聽世界
- 讓機器獨立思考
自動駕駛
在駕駛領(lǐng)域中,引入物體識別技術(shù)將大大降低交通事故發(fā)生的概率。
淘寶京東使用物體識別技術(shù)
公司業(yè)務(wù)需求
近期產(chǎn)品提出物體識別的相應(yīng)需求,能識別出家長和老師發(fā)送圖片中的物體,來開展相應(yīng)的業(yè)務(wù)。以下是一張海邊游玩的照片。
深度學(xué)習(xí)簡介
深度學(xué)習(xí)的位置
深度學(xué)習(xí)分別屬于人工智能和機器學(xué)習(xí)的一部分。與深度學(xué)習(xí)相并行的另外一種機器學(xué)習(xí)方法,被稱之為傳統(tǒng)的機器學(xué)習(xí)(例如svm、邏輯回歸)。
深度學(xué)習(xí)概念
人工神經(jīng)網(wǎng)絡(luò)是一個分層的有向圖,第一層輸入節(jié)點接受輸入的信息,也稱為輸入層。來自這些點的數(shù)值按照它們輸出的弧的權(quán)重(wn),進行線性加權(quán)(得到G),然后再做一次函數(shù)變化f(G),賦給第二層的節(jié)點Y。
第二層的節(jié)點照此將數(shù)值向后傳遞,直到第三層節(jié)點,如此一層層傳遞,直到最后一層,最后一層又被稱為輸出層。在模式分類時,一個模式(圖像、語音、文字等)的特征值(比如坐標(biāo)),從輸入層開始,按照上面的規(guī)則和公式一層層向后傳遞。最后在輸出層,哪個節(jié)點的數(shù)值最大,輸入的模式就被分在了哪一類。
------------------引自《數(shù)學(xué)之美—Google大腦和人工神經(jīng)網(wǎng)絡(luò)》
深度學(xué)習(xí)優(yōu)勢
神經(jīng)網(wǎng)絡(luò)與傳統(tǒng)的機器學(xué)習(xí)相比:
- 能支持更復(fù)雜的分類邊界
- 非線性表征更加豐富
- 準(zhǔn)確率會隨著數(shù)據(jù)集的增加而突破傳統(tǒng)學(xué)習(xí)的瓶頸
- 與svm相比,在大數(shù)據(jù)集上收斂的更快
- 輕量級神經(jīng)網(wǎng)絡(luò)具備高性能的前向傳播,方便部署到移動設(shè)備
深度學(xué)習(xí)基礎(chǔ)知識
參考:https://www.cnblogs.com/wj-1314/p/9754072.html
感知機
可以簡單的理解為是線性分類。假設(shè)訓(xùn)練數(shù)據(jù)集是線性可分的,感知機學(xué)習(xí)的目標(biāo)是求得一個能夠?qū)⒂?xùn)練數(shù)據(jù)集正實例點和負實例點完全正確分開的分離超平面。
感知機重點包含以下兩點:
- 線性加權(quán)
- 依靠損失函數(shù)進行權(quán)重優(yōu)化
數(shù)學(xué)公式略,將在其他博文中進行闡述。
感知機的缺陷:只支持線性分類,對于簡單的異或問題也不能進行分類。以下是異或問題中最簡單的情況,可以看到無論哪一條直線都不能進行完美的分割。
激活函數(shù)
針對于感知機不能表達非線性的問題,激活函數(shù)誕生了。
在人工神經(jīng)網(wǎng)絡(luò)中,規(guī)定神經(jīng)元函數(shù)只能對輸入變量(指向他的節(jié)點的值)線性組合后的結(jié)果進行一次非線性變換。
這次非線性變化成為“激活函數(shù)”
----《數(shù)學(xué)之美》
為了神經(jīng)網(wǎng)絡(luò)的通用性,每一層的非線性變化都選擇同一類函數(shù)。
激活函數(shù)包括:
- relu
- sigmoid
- tanh
- 等等
激活函數(shù)參考博客:https://blog.csdn.net/tyhj_sf/article/details/79932893
多層感知機
多層感知機(MLP,Multilayer Perceptron)也叫人工神經(jīng)網(wǎng)絡(luò)(ANN,Artificial Neural Network),除了輸入輸出層,它中間可以有多個隱層,最簡單的MLP只含一個隱層,即三層的結(jié)構(gòu)
- 輸入層,輸入特征數(shù)據(jù)等加工或者沒有加工過的原始數(shù)據(jù)
- 隱含層,隱含層可以很多,resnet有128層的,就是說的隱含層
- 輸出層,輸出最后的計算結(jié)果,很多神經(jīng)網(wǎng)絡(luò)里面都把輸出層定義為概率值
多層感知機等同于全連接層,信息每向下傳遞一個神經(jīng)元,都會產(chǎn)生n*n的計算量(計算量會隨著輸入的維度增大而變得非常恐怖)
卷積神經(jīng)網(wǎng)絡(luò)
卷積神經(jīng)網(wǎng)絡(luò)是近年發(fā)展起來的,并引起廣泛重視的一種高效識別方法,20世紀60年代,Hubel和Wiesel在研究貓腦皮層中用于局部敏感和方向選擇的神經(jīng)元時發(fā)現(xiàn)其獨特的網(wǎng)絡(luò)結(jié)構(gòu)可以有效地降低反饋神經(jīng)網(wǎng)絡(luò)的復(fù)雜性,繼而提出了卷積神經(jīng)網(wǎng)絡(luò)(Convolutional Neural Networks-簡稱CNN)
參考資料:https://www.cnblogs.com/wj-1314/p/9754072.html
卷積的原理與人眼觀察事物極其相似,過程都是邊緣 -> 局部 -> 整體。卷積神經(jīng)網(wǎng)絡(luò)的核心就是使用多個局部特征來影響分類結(jié)果。
全連接的計算量非常大。而且是以整體來計算,沒有進行有效的特征提取,即使權(quán)重最終達到了收斂效果,也不能很好的進行預(yù)測。
卷積神經(jīng)網(wǎng)絡(luò)則不同,每次卷積完畢后,傳入下一層的數(shù)據(jù)大大降低了維度,而且經(jīng)過卷積,獲得了眾多局部特征,后面的層對這些特征數(shù)據(jù)進行訓(xùn)練,將變得既簡單又高效。
卷積層
簡單來說,卷積層用于特征提取。
根據(jù)卷積核的滑動,獲取到一個新的特征數(shù)據(jù)(Convolved Feature)。這個特征數(shù)據(jù)不是那么直觀,來看一下實物的效果。
針對于不同的通道(rgb)進行卷積后,會得到邊緣輪廓的圖。
池化層
池化層用于降低參數(shù),而降低參數(shù)的方法當(dāng)然是刪除參數(shù),保留最有效的參數(shù)。
一般我們有最大池化和平均池化。
- 最大池化是現(xiàn)在使用最多的,可以突出局部特征
- 平均池化則考慮了所有參數(shù),而計算出了平均值
需要注意的是,池化層一般放在卷積層后面。所以池化層池化的是卷積層的輸出。
模型訓(xùn)練
本博客重點關(guān)注有監(jiān)督的訓(xùn)練。在訓(xùn)練之前需要有一批標(biāo)注好的數(shù)據(jù),即訓(xùn)練數(shù)據(jù)。為了能在訓(xùn)練過程中動態(tài)的觀測模型的準(zhǔn)確率,同樣也需要一批標(biāo)注數(shù)據(jù)(推薦為訓(xùn)練數(shù)據(jù)/測試數(shù)據(jù)比例為4/1)
前向傳播
前向傳播,即訓(xùn)練數(shù)據(jù)在神經(jīng)網(wǎng)絡(luò)里從輸入層到輸出層的方向傳播一次,最終得到輸出層的輸出結(jié)果,即在每個分類的概率值。
反向傳播與參數(shù)優(yōu)化
用數(shù)據(jù)語言來表達:假設(shè)C為一個成本函數(shù)(Cost Function),它表示根據(jù)人工神經(jīng)網(wǎng)絡(luò)的輸出值(分類結(jié)果概率)和實際訓(xùn)練數(shù)據(jù)中的輸出值之間的差距。現(xiàn)在,訓(xùn)練人工神經(jīng)網(wǎng)絡(luò)的問題就變成了一個最優(yōu)化的問題,說的通俗點就是數(shù)學(xué)中的“找最大(最小)值”的問題。解決最優(yōu)化為題的常用方法是梯度下降法(Gradient Descent)
注:這里存在一個局部最優(yōu)解的問題,不過已經(jīng)被證明:在深度神經(jīng)網(wǎng)絡(luò)中,即使收斂過程進入了局部最優(yōu),最終結(jié)果也與全局最優(yōu)沒有明顯差異。
深度學(xué)習(xí)服務(wù)端框架
tensorFlow
2015年11月谷歌(Google)出品,基于Python和C++編寫。GitHub上最熱,谷歌搜索最多,使用人數(shù)最多(筆者也是其中之一),大多數(shù)網(wǎng)上招聘工作描述中也提到了它。由于Google在深度學(xué)習(xí)領(lǐng)域的巨大影響力和強大的推廣能力,TensorFlow一經(jīng)推出就獲得了極大的關(guān)注,并迅速成為如今用戶最多的深度學(xué)習(xí)框架。2019年3月已發(fā)布最新的TensorFlow2.0 版本。
官方網(wǎng)站:https://www.tensorflow.org/
優(yōu)點:
- 自帶tensorboard可視化工具,能夠讓用戶實時監(jiān)控觀察訓(xùn)練過程
- 擁有大量的開發(fā)者,有詳細的說明文檔、可查詢資料多
- 支持多GPU、分布式訓(xùn)練,跨平臺運行能力強
- 具備不局限于深度學(xué)習(xí)的多種用途,還有支持強化學(xué)習(xí)和其他算法的工具
缺點:
- 頻繁變動的接口。TensorFlow的接口一直處于快速迭代之中,并且沒有很好地考慮向后兼容性,這導(dǎo)致現(xiàn)在許多開源代碼已經(jīng)無法在新版的TensorFlow上運行,同時也間接導(dǎo)致了許多基于TensorFlow的第三方框架出現(xiàn)BUG
- 接口設(shè)計過于晦澀難懂,在設(shè)計TensorFlow時,創(chuàng)造了圖、會話、命名空間、PlaceHolder等諸多抽象概念,對初學(xué)者來說較難上手
- 運行明顯比其他框架速度慢
keras
Keras 于2015年3月首次發(fā)布,擁有“為人類而不是機器設(shè)計的API”,得到Google的支持。它是一個用于快速構(gòu)建深度學(xué)習(xí)原型的高層神經(jīng)網(wǎng)絡(luò)庫,由純Python編寫而成,以TensorFlow,CNTK,Theano和MXNet為底層引擎,提供簡單易用的API接口,能夠極大地減少一般應(yīng)用下用戶的工作量。
如果你是深度學(xué)習(xí)的初學(xué)者,想要快速入門,建議從Keras開始。
官方網(wǎng)站:https://keras.io
優(yōu)點:
- 更簡潔,更簡單的API
- 豐富的教程和可重復(fù)使用的代碼
- 更多的部署選項(直接并且通過TensorFlow后端),更簡單的模型導(dǎo)出
缺點:
- 過度封裝導(dǎo)致喪失靈活性,導(dǎo)致用戶在新增操作或是獲取底層的數(shù)據(jù)信息時過于困難
- 初學(xué)者容易依賴于 Keras 的易使用性而忽略底層原理
pytorch
PyTorch于2016年10月發(fā)布,是一款專注于直接處理數(shù)組表達式的低級API。 前身是 Torch(一個基于 Lua 語言的深度學(xué)習(xí)庫)。Facebook 人工智能研究院對PyTorch提供了強力支持。 PyTorch 支持動態(tài)計算圖,為更具數(shù)學(xué)傾向的用戶提供了更低層次的方法和更多的靈活性,目前許多新發(fā)表的論文都采用PyTorch作為論文實現(xiàn)的工具,成為學(xué)術(shù)研究的首選解決方案。
如果你是一名科研工作者,傾向于理解你的模型真正在做什么,那么就考慮選擇PyTorch。
官方網(wǎng)站:https://pytorch.org/
Caffe/Caffe2.0
Caffe的全稱是Convolutional Architecture for Fast Feature Embedding,它是一個清晰、高效的深度學(xué)習(xí)框架,于2013年底由加州大學(xué)伯克利分校開發(fā),核心語言是C++。它支持命令行、Python和MATLAB接口。Caffe的一個重要特色是可以在不編寫代碼的情況下訓(xùn)練和部署模型。
具體介紹見下文。
caffe框架
為何選擇caffe
我們暫時先選擇caffe框架作為分享目標(biāo),原因如下:
- 與ncnn的兼容性好(最重點)
- 不需要寫代碼就可以實現(xiàn)訓(xùn)練(可以作為深度學(xué)習(xí)的突破口)
- 支持python接口,可以豐富編程化實現(xiàn)
- 豐富的demo實現(xiàn)等
caffe環(huán)境搭建
推薦ubuntu系統(tǒng),參考博客:https://blog.csdn.net/wangjie5540/article/details/97786182
mac系統(tǒng)也可搭建,參考博客:https://blog.csdn.net/wangjie5540/article/details/99571832
caffe使用了眾多的依賴庫,再加上caffe年久失修,出現(xiàn)編譯兼容問題也不奇怪。推薦大家在ubuntu上進行編譯,可以驅(qū)動gpu,mac的最新14.14不支持n卡,據(jù)說需要降到14.13才可以。
caffe基礎(chǔ)
針對于神經(jīng)網(wǎng)絡(luò)的模型,caffe設(shè)計了對應(yīng)的概念。并且使用caffe來訓(xùn)練模型的過程非常簡單,甚至都不用寫一行代碼,僅僅改改配置文件也同樣能直接開始訓(xùn)練(當(dāng)然,用python去寫訓(xùn)練過程的話,會更加的靈活)。
數(shù)據(jù)集
- 原始數(shù)據(jù),本文主要針對的是圖片數(shù)據(jù),可能有不同的格式(image格式、bytes格式、lmdb格式等)
- 標(biāo)注數(shù)據(jù),監(jiān)督學(xué)習(xí),必須進行標(biāo)注
caffe傾向于先把數(shù)據(jù)集轉(zhuǎn)化成lmdb或者hdf5格式,然后輸入神經(jīng)網(wǎng)絡(luò)進行訓(xùn)練。
模塊概要圖
概要:
- 使用數(shù)據(jù)構(gòu)建腳本,構(gòu)建訓(xùn)練數(shù)據(jù)和測試數(shù)據(jù)
- caffe train命令加載solver的prototxt配置
- solver配置加載神經(jīng)網(wǎng)絡(luò)配置
- 神經(jīng)網(wǎng)絡(luò)對接訓(xùn)練數(shù)據(jù)和測試數(shù)據(jù)
- 成千上萬次迭代,最終按照solver中的配置策略,周期性生成權(quán)重模型文件
solver(prototxt) 執(zhí)行者配置
超參數(shù)配置文件。
超參數(shù)的概念如下:
在機器學(xué)習(xí)的上下文中,超參數(shù)是在開始學(xué)習(xí)過程之前設(shè)置值的參數(shù),而不是通過訓(xùn)練得到的參數(shù)數(shù)據(jù)。通常情況下,需要對超參數(shù)進行優(yōu)化,給學(xué)習(xí)機選擇一組最優(yōu)超參數(shù),以提高學(xué)習(xí)的性能和效果
神經(jīng)網(wǎng)絡(luò)可視化
http://ethereon.github.io/netscope/#/editor
下面是對lenet的可視化,可以清楚的看到lenet的全貌。
- mnist數(shù)據(jù)輸入
- conv1,第一次卷積層
- pool1,第一池化層
- conv2,第二次卷積層
- pool2,第二次池化層
- ip1,全連接層(即多層感知機)
- relu1,激活層
- ip2,全連接層
- loss,損失層(同時激發(fā)bn反向傳播操作)
caffe中的基礎(chǔ)概念
blobs
- 對待處理數(shù)據(jù)帶一層封裝用于在Caffe中通信傳遞
- 也為CPU和GPU間提供同步能力
- 數(shù)學(xué)上,是一個N維的C風(fēng)格的存儲數(shù)組
總的來說,Caffe使用Blob來交流數(shù)據(jù),其是Caffe中標(biāo)準(zhǔn)的數(shù)組與統(tǒng)一的內(nèi)存接口,它是多功能的,在不同的應(yīng)用場景具有不同的含義,如可以是:batches of images, model parameters, and derivatives for optimization等
作者:漚江一流
鏈接:https://www.jianshu.com/p/0ac09c3ffec0
layer 神經(jīng)層
layer是caffe神經(jīng)網(wǎng)絡(luò)的基本組成單元。layer包括不同的種類:
- Data,也就是blob的層
- Convolution,卷積層
- Pooling,池化層
- InnerProduct,全連接
- SoftmaxWithLoss,激活函數(shù)+loss層
不同的層次對應(yīng)了神經(jīng)網(wǎng)絡(luò)中的不通過概念。另外,每種類型的層在caffe的源碼中有特定的實現(xiàn),之后會在其他博客中展開討論,這里不再贅述。
net 神經(jīng)網(wǎng)絡(luò)
net是指神經(jīng)網(wǎng)絡(luò)定義,可以認為是layer的總和。在python版本編程中會出現(xiàn)net的概念。
forward/backward 前向傳播/反向傳播
forward和backward在python編程版本中會出現(xiàn),手動執(zhí)行會觸發(fā)一次前向傳播或反向傳播(python實現(xiàn)的caffe訓(xùn)練最終的本質(zhì)是在循環(huán)中每次手動觸發(fā)forward函數(shù),重點看一下本博客的caffe+mnist的python實現(xiàn)注釋版)。
caffe+mnist數(shù)據(jù)集+lenet
參考博客:https://blog.csdn.net/wangjie5540/article/details/98615226
python實現(xiàn)mnist(注釋版):https://gitee.com/simple_projects/caffe_learning/blob/master/01-learning-lenet-mine.ipynb
caffe+cifar10+caffenet
非常類似mnist數(shù)據(jù)集,參考:https://blog.csdn.net/wangjie5540/article/details/98615226
caffe+cifar10+mobilenet
參考:https://github.com/shicai/MobileNet-Caffe.git
shicai的mobilenet提供了預(yù)訓(xùn)練模型,可以直接進行數(shù)據(jù)預(yù)測。
大家肯定想,預(yù)訓(xùn)練模型沒什么意思,要自己訓(xùn)練才來實際。
參考:https://blog.csdn.net/lwplwf/article/details/82415525,可以使用cifar10進行模型訓(xùn)練。
(ps,作者用cpu訓(xùn)練了幾天,最終迭代了19w次,最終準(zhǔn)確率在70%,沒有達到很好的收斂效果。之后準(zhǔn)備好gpu的機器,還會再次訓(xùn)練,以觀后效)
注:cifar10的數(shù)據(jù)集進行模型訓(xùn)練的時候,出現(xiàn)mean的概念(即均值,rgb每個通道上的像素的平均值)。這樣做的目的是讓個像素的值以0為對稱點進行均勻分布,訓(xùn)練過程更容易收斂。有兩種獲取均值的方法:
- 以數(shù)據(jù)集為目標(biāo),把每個通道上的像素值全部加和,然后求平均(caffe的cifar10就是使用的這種方法)
- 直接使用均值(128,128,128),簡單暴力。(mobilenet+ssd的訓(xùn)練過程中就是這么做的,最終也能收斂)
以上兩種方法,暫時沒有證實哪個效果最好。
caffe+voc2012+vgg(finetune)+ssd(物體檢測模型)
參考:https://github.com/weiliu89/caffe.git
voc的數(shù)據(jù)集需要在外網(wǎng)下載,時間要好久好久。。我已經(jīng)把這些數(shù)據(jù)都下載完畢,上傳到云盤。以下是下載地址:https://download.csdn.net/download/wangjie5540/11598810
由于本次是遷移訓(xùn)練,預(yù)訓(xùn)練模型是vggnet,還需要下載vggnet,地址是:https://download.csdn.net/download/wangjie5540/11603902
注:博主用cpu訓(xùn)練跑了兩天,還沒有跑到第一次的快照地點。如果想自己訓(xùn)練的話,就選gpu的機器吧。
輕量級客戶端框架-ncnn
ncnn簡介
git地址:https://github.com/Tencent/ncnn
ncnn 是一個為手機端極致優(yōu)化的高性能神經(jīng)網(wǎng)絡(luò)前向計算框架。ncnn 從設(shè)計之初深刻考慮手機端的部署和使用。無第三方依賴,跨平臺,手機端 cpu 的速度快于目前所有已知的開源框架。基于 ncnn,開發(fā)者能夠?qū)⑸疃葘W(xué)習(xí)算法輕松移植到手機端高效執(zhí)行,開發(fā)出人工智能 APP,將 AI 帶到你的指尖。ncnn 目前已在騰訊多款應(yīng)用中使用,如 QQ,Qzone,微信,天天P圖等。
支持大部分常用的 CNN 網(wǎng)絡(luò)
- Classical CNN: VGG AlexNet GoogleNet Inception …
- Practical CNN: ResNet DenseNet SENet FPN …
- Light-weight CNN: SqueezeNet MobileNetV1/V2/V3 ShuffleNetV1/V2 MNasNet …
- Detection: MTCNN facedetection …
- Detection: VGG-SSD MobileNet-SSD SqueezeNet-SSD MobileNetV2-SSDLite …
- Detection: Faster-RCNN R-FCN …
- Detection: YOLOV2 YOLOV3 MobileNet-YOLOV3 …
- Segmentation: FCN PSPNet UNet …
ncnn+caffe+mobilenet實戰(zhàn)
ncnn環(huán)境搭建
先下載release版本的ncnn,我這里現(xiàn)在ncnn-20190611
$ cd <ncnn-root-dir> $ mkdir -p build-android-armv7 $ cd build-android-armv7$ cmake -DCMAKE_TOOLCHAIN_FILE=$ANDROID_NDK/build/cmake/android.toolchain.cmake \-DANDROID_ABI="armeabi-v7a" -DANDROID_ARM_NEON=ON \-DANDROID_PLATFORM=android-14 ..# if you want to enable vulkan, platform api version >= android-24 is needed $ cmake -DCMAKE_TOOLCHAIN_FILE=$ANDROID_NDK/build/cmake/android.toolchain.cmake \-DANDROID_ABI="armeabi-v7a" -DANDROID_ARM_NEON=ON \-DANDROID_PLATFORM=android-24 -DNCNN_VULKAN=ON ..$ make -j4 $ make installpick build-android-armv7/install folder for further jni usage編譯完成后,生成以下文件
支持庫和頭文件供android的arm-v7a使用
模型轉(zhuǎn)化(caffe格式-> ncnn格式)
首先需要編譯caffe的環(huán)境。
參考:
https://blog.csdn.net/wangjie5540/article/details/97786182
https://blog.csdn.net/wangjie5540/article/details/99571832
源碼解析
文件目錄
├── README.md ├── app │ ├── build.gradle // android工程配置 │ ├── proguard-rules.pro // 混淆配置 │ └── src │ ├── androidTest │ │ └── java │ │ └── com │ │ └── ztjy │ │ └── ncnndemo │ │ └── ExampleInstrumentedTest.java │ ├── main │ │ ├── AndroidManifest.xml │ │ ├── assets │ │ │ ├── mobilenet_v2.bin // mobilenet權(quán)重文件 │ │ │ ├── mobilenet_v2.param.bin // 神經(jīng)網(wǎng)絡(luò)參數(shù)文件 │ │ │ └── synset.txt // 分類索引文件 │ │ ├── cpp │ │ │ ├── CMakeLists.txt │ │ │ ├── include // ncnn的頭文件 │ │ │ │ ├── allocator.h │ │ │ │ ├── benchmark.h │ │ │ │ ├── blob.h │ │ │ │ ├── caffe.pb.h │ │ │ │ ├── command.h │ │ │ │ ├── cpu.h │ │ │ │ ├── gpu.h │ │ │ │ ├── layer.h │ │ │ │ ├── layer_type.h │ │ │ │ ├── layer_type_enum.h │ │ │ │ ├── mat.h │ │ │ │ ├── mobilenet_v2.id.h │ │ │ │ ├── mobilenet_v2.mem.h │ │ │ │ ├── modelbin.h │ │ │ │ ├── net.h │ │ │ │ ├── opencv.h │ │ │ │ ├── option.h │ │ │ │ ├── paramdict.h │ │ │ │ ├── pipeline.h │ │ │ │ └── platform.h │ │ │ ├── jniLibs │ │ │ │ └── armeabi-v7a │ │ │ │ └── libncnn.a // ncnn靜態(tài)庫 │ │ │ └── native-lib.cpp │ │ ├── java │ │ │ └── com │ │ │ └── ztjy │ │ │ └── ncnndemo │ │ │ ├── MainActivity.java // 主窗體 │ │ │ ├── NcnnJni.java // jni交互文件 │ │ │ └── PhotoUtil.java // 圖片工具文類(從相冊中取文件) │ │ └── res │ │ ├── drawable │ │ │ └── ic_launcher_background.xml │ │ ├── drawable-v24 │ │ │ └── ic_launcher_foreground.xml │ │ ├── layout │ │ │ └── activity_main.xml │ │ ├── mipmap-anydpi-v26 │ │ │ ├── ic_launcher.xml │ │ │ └── ic_launcher_round.xml │ │ ├── mipmap-hdpi │ │ │ ├── ic_launcher.png │ │ │ └── ic_launcher_round.png │ │ ├── mipmap-mdpi │ │ │ ├── ic_launcher.png │ │ │ └── ic_launcher_round.png │ │ ├── mipmap-xhdpi │ │ │ ├── ic_launcher.png │ │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxhdpi │ │ │ ├── ic_launcher.png │ │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxxhdpi │ │ │ ├── ic_launcher.png │ │ │ └── ic_launcher_round.png │ │ └── values │ │ ├── colors.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── java │ └── com │ └── ztjy │ └── ncnndemo │ └── ExampleUnitTest.java ├── build.gradle ├── gradle │ └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradle.properties ├── gradlew ├── gradlew.bat └── settings.gradle執(zhí)行流程
https://www.processon.com/view/link/5d5cfe08e4b08b95b82695bb
重點代碼
java層代碼
// predict imageprivate void predict_image(String image_path) {// picture to float arrayBitmap bmp = PhotoUtil.getScaleBitmap(image_path);Bitmap rgba = bmp.copy(Bitmap.Config.ARGB_8888, true);// resize to 227x227Bitmap input_bmp = Bitmap.createScaledBitmap(rgba, ddims[2], ddims[3], false);try {// Data format conversion takes too long// Log.d("inputData", Arrays.toString(inputData));long start = System.currentTimeMillis();// get predict result(調(diào)用jni層代碼,進行預(yù)測)float[] result = squeezencnn.detect(input_bmp);long end = System.currentTimeMillis();Log.d(TAG, "origin predict result:" + Arrays.toString(result));long time = end - start;Log.d(TAG, String.valueOf(result.length));// show predict result and timeint r = get_max_result(result);Log.d(TAG, r + "");Log.d(TAG, resultLabel.toString());Log.d(TAG, resultLabel.get(r));Log.d(TAG, result[r] + "");Log.d(TAG, time + "");String show_text = "result:" + r + ",name:" + resultLabel.get(r) + "\nprobability:" + result[r] + "\ntime:" + time + "ms";Log.d(TAG, show_text);result_text.setText(show_text);} catch (Exception e) {e.printStackTrace();}}jni層代碼
// public native String Detect(Bitmap bitmap); JNIEXPORT jfloatArray JNICALL Java_com_ztjy_ncnndemo_NcnnJni_detect(JNIEnv *env, jobject thiz, jobject bitmap) {// ncnn from bitmapncnn::Mat in;{AndroidBitmapInfo info;// 獲取位圖信息AndroidBitmap_getInfo(env, bitmap, &info);// 獲取位圖寬高int width = info.width;int height = info.height;// demo只支持rgba格式的圖片if (info.format != ANDROID_BITMAP_FORMAT_RGBA_8888)return NULL;void *indata;AndroidBitmap_lockPixels(env, bitmap, &indata);// 把像素轉(zhuǎn)換成data,并指定通道順序in = ncnn::Mat::from_pixels((const unsigned char *) indata, ncnn::Mat::PIXEL_RGBA2BGR,width, height);AndroidBitmap_unlockPixels(env, bitmap);}// ncnn_net// std::vector<float> cls_scores;{// 減去均值和乘上比例(來源與caffe神經(jīng)網(wǎng)絡(luò)的配置文件,即prototxt文件)const float mean_vals[3] = {103.94f, 116.78f, 123.68f};const float scale[3] = {0.017f, 0.017f, 0.017f};// 設(shè)置均值與標(biāo)準(zhǔn)化參數(shù)in.substract_mean_normalize(mean_vals, scale);// 創(chuàng)建ncnn前向傳播的結(jié)果提取器ncnn::Extractor ex = ncnn_net.create_extractor();// 如果不加密使用ex.input("data", in);ex.input(mobilenet_v2_param_id::BLOB_data, in);ncnn::Mat out;// 如果不加密是使用ex.extract("prob", out);ex.extract(mobilenet_v2_param_id::BLOB_prob, out);int output_size = out.w;jfloat *output[output_size];for (int j = 0; j < out.w; j++) {output[j] = &out[j];}// 獲取結(jié)果預(yù)測結(jié)果,并返回給android層jfloatArray jOutputData = env->NewFloatArray(output_size);if (jOutputData == nullptr) return nullptr;env->SetFloatArrayRegion(jOutputData, 0, output_size,reinterpret_cast<const jfloat *>(*output)); // copyreturn jOutputData;} }效果展示
caffe+mobilenet分類
其他工程的效果圖
https://github.com/chehongshu/ncnnforandroid_objectiondetection_Mobilenetssd.git
ncnn+mobilenet-ssd
相關(guān)學(xué)習(xí)資料
教學(xué)視頻
唐宇迪-深度學(xué)習(xí)Caffe框架入門視頻課程:https://edu.csdn.net/course/detail/3506
會寫代碼的好廚師-Caffe實戰(zhàn)入門:https://www.imooc.com/learn/1040
開源項目
caffe官網(wǎng):https://github.com/BVLC/caffe
ncnn:https://github.com/Tencent/ncnn.git
ncnn+mobilenet-ssd:https://github.com/chehongshu/ncnnforandroid_objectiondetection_Mobilenetssd
shicai_mobilenet:https://github.com/shicai/MobileNet-Caffe.git
weiliu89:https://github.com/weiliu89/caffe.git(需要check_out到ssd分支)
參考博客
在Android手機上使用騰訊的ncnn實現(xiàn)圖像分類:
https://blog.csdn.net/qq_33200967/article/details/82421089
總結(jié)
以上是生活随笔為你收集整理的深度学习-服务端训练+android客户端物体识别实战(caffe入门教程+mobilenet+ncnn+android)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: vm虚拟远程部署windows驱动
- 下一篇: 深度学习attention原理_深度学习