本文首發于簡書——何時夕,搬運轉載請注明出處,否則将追究版權責任。
被處理的圖檔
最近學了近一個月半月的深度學習,是以想檢驗一下學習成果。正好畢設是圖像處理APP的實作,是以就把快速風格遷移的前饋神經網絡通過Tensorflow for Android移植到了APP上面,作為濾鏡快速風格遷移的效果還挺不錯,就是速度有點慢。可能和現在Android端的深度學習還不支援gpu有關吧。
1.關于MyPhotoShop
這是一個圖檔處理APP,裡面使用了Opencv、深度學習、MVVM、Databinding、RxJava、各種設計模式等等,在後面一段時間我會寫一系列部落格來一步步剖析這個項目,希望大家能多多關注。
1.效果
素描風格
梵高星夜風格
2.項目相關
- 1.github位址: MyPhotoShop 圖檔處理APP 項目位址 。
- 2.apk下載下傳: MyPhotoShop 下載下傳位址 ,apk挺大的,不過大部分是神經網絡模型檔案,是以實在減不下來
3.缺點
- 1.沒有元件化
- 2.沒有混淆
- 3.有些地方抽象不夠
2.深度學習和神經網絡的基本概念
1.什麼是深度學習
- 1.AI--》機器學習--》深度學習,前面三個概念是遞進的,簡單來說深度學習是機器學習的一種,深度學習就是利用機器來學習很多資料,而機器學習又是實作AI的一種方式。
- 2.在深度學習中有兩個重要的東西:資料和神經網絡。在深度學習中有兩個重要的過程:訓練和測試
- 1.資料和網絡:
- 1.資料:我們想象一個簡單的圖檔分類場景,我們有10000張已經被人工分好類的圖檔,每張圖檔都有一個正确的分類,比如貓、狗等等。
- 2.網絡:這裡的神經網絡我們可以想象成一個函數,我們的輸入是一張圖檔,輸出則是這張圖檔在每個分類下面的分數。也就是一個分數的數組。
- 2.訓練和測試:
- 1.訓練:在訓練的時候我們會将圖檔集中的圖檔一次次的輸入到神經網絡裡面去,然後會一次次得到該圖檔在每個分類下的分數,每當我們得出了一個分數數組之後我們可以計算目前的神經網絡的損失值(目前的網絡準确率越高損失值越低),有了損失值,我們的目标就是降低損失值。了解導數的同學都知道我們可以通過求導損失值函數得到讓損失值降低的梯度方向,然後回報到神經網絡中。就這樣一次次的循環,讓損失值降到最低。
- 2.測試:當我們将神經網絡訓練到了一個最佳的狀态,我們就可以将我們需要進行分類的圖檔,輸入到神經網絡中,得到最終神經網絡對該圖檔分類的結果。
- 3.總結:深度學習到底是怎麼學習的呢?我們可以看見我們的訓練資料是經過人的處理的,那麼深度學習的過程就是将人的處理過程固化到我們的神經網絡中,最終讓神經網絡來代替人工處理的過程。
- 4.上面隻是介紹深度學習的基本流程,如果要更深入的了解可以看 這篇部落格
- 1.資料和網絡:
2.什麼是神經網絡
我們在上一節中說到了,最終人處理資料的過程通過我們的訓練被固化到神經網絡中去了。下面我會簡單介紹一下前面說到的神經網絡。
- 1.還是在簡單的圖檔分類場景:
- 1.我們假設圖檔為x的大小為100 * 100(我們把圖檔平鋪成為1 * 10000的矩陣),圖檔一共有10個分類。
- 2.那麼一個兩層的神經網絡就是這樣的:y = x * w1 * w2(w1為 10000 * a的矩陣,w2為a * 10的矩陣),這裡最終y就是一張圖檔在各個分類下的分數,式子中的乘法是矩陣乘法。
- 3.當然層數更多的神經網絡就是有更多的w,我們w1 和 w2中的a可以自己定義。
- 2.解釋一下y = x * w1 * w2:
- 1.研究表明我們在看x這張圖檔的時候,我們會先看圖檔的輪廓,這裡我們大腦中看圖檔輪廓的神經元就相當于w1
- 2.看完輪廓之後我們會對這個圖檔中的東西有基本感覺,判斷這張圖檔屬于哪些類别,這裡的類别就是x * w1的結果
- 3.2中的結果會被輸入大腦中下一層神經元,這裡的神經元就相當于w2,經過w2之後我們就會輸出一個結果這裡就是y。
- 4.當然人的神經元層數遠比上面說到的多
- 3.訓練y = x * w1 * w2的過程以人做對比就相當于:我們有一堆圖檔給一個啥也不懂的小孩看,剛開始他肯定輸出的結果都是錯的,但是我們隻要每次糾正一下他的錯誤,那麼他腦袋中的神經元(w)就會不斷的修改然後識别的準确率不斷提高。
3.Android中的Tensorflow
這一節将會介紹如何在Android中使用已經訓練好的神經網絡
1.開始
本篇文章中,我隻會以一個demo為例子進行講解,前面提到的MyPhotoShop項目會另起一個專題進行剖析。
- 1.demo位址: github位址
- 2.引入Tensorflow:compile 'org.tensorflow:tensorflow-android:+'
2.Tensorflow中的概念
- 1.圖(graph):我們在前面講解了一個神經網絡是什麼樣子的,在Tensorflow中神經網絡的每個神經元w都屬于圖中的一個節點,神經網絡全部的節點就構成了一個有向無環圖也就是Tensorflow的圖的一部分。當然Tensorflow的圖中除了神經網絡的節點外,還有其他輔助的操作:比如圖檔解碼、圖檔編碼、圖檔預處理操作等等。我們舉一個圖的例子就是:圖檔a--》解碼圖檔産生b--》處理b産生圖檔資料矩陣c(1 * 10000)--》c與w1(10000 * x)矩陣相乘産生d(1 * x)--》d與w2(x * 10)矩陣相乘産生e(1 * 10)--》選出e中值最大的分類,神經網絡就判斷圖檔a是這種分類的圖檔。
- 2.節點(node):每個節點都是圖的一部分,每個節點有:入參、出參、具體操作函數(比如矩陣乘法)、可能有神經元值w。
- 3.TensorFlowInferenceInterface:一個Tensorflow中訓練的上下文,在不同語言中名字不同。内部包含了一個訓練中需要的全部執行個體。
3.demo代碼講解
我們本次demo中隻涉及Tensorflow在Android中神經網絡模型的使用,并不涉及訓練的過程。原因有兩個:1.移動端并不适合訓練神經網絡 2.Tensorflow for Android沒有訓練的API。
- 1.我這次使用的神經網絡是已經訓練好的快速風格遷移網絡
- 2.對于模型我們的輸入是:一張圖檔轉化為的float類型的張量,大小為(1 * 800 * 600 * 3),輸入節點的名字是padsss:0,這裡的名字是在訓練過程中定義的。
- 3.對于這個模型我們的輸出是:大小為(1 * 780 * 680 * 3)的float類型張量。輸出節點的名字是squeezesss:0,名字也是在訓練過程中定義的。
代碼片段1
- 4.我們看代碼,先用RxPermission擷取了一下權限,擷取成功之後将assets中需要處理的圖檔寫入到sd卡中一遍後面使用,進入make()方法
代碼片段2
- 5.将4中的圖檔讀取到記憶體中
- 6.以ARGB為例我們知道Bitmap中每個像素是以int十六進制儲存像素的,類似這種形式FFFFFFFF,那麼每兩位就是一個通道的數值,上限是256。是以接下來就是将Bitmap中的像素值,轉化為float類型的數組,數組大小是(800 * 600 * 3)。
- 7.建立了一個TensorFlowInferenceInterface對象,入參是AssetManager和模型檔案,這裡就表示将神經網絡在記憶體中建立起來
- 8.輸出一下每個節點的名字
- 9.向神經網絡中傳入輸入節點的名字、輸入節點的資料、資料張量的次元
- 10.運作神經網絡,入參是輸出節點的名字
- 11.神經網絡的運作時阻塞的,是以運作好了之後,就能擷取資料了,這裡将資料存入(780 * 580 * 3)的float數組中。
- 12.将float數組重新整合成Bitmap的像素值,然後寫入Bitmap中。
4.注意點
- 1.demo運作的時候速度會比較慢,耐心等待一下
- 2.我運作的裝置是:小米mix2、Android8.0。其他裝置可能會有問題,要麼就是速度非常慢,還可能是cpu或者系統版本不支援。
4.總結
在Android中運作一個已經訓練好的神經網絡還是比較簡單的,隻要知道了輸入輸出,就像運作一個普通的函數那麼簡單。至于如何去訓練一個神經網絡,那就是另外的故事了,可以關注我的我學機器學習文集!裡面會持續更新我學習機器學習的心得和體會。