android中的深度學習——快速風格遷移

何時夕發表於2018-05-19

本文首發於微信公眾號——世界上有意思的事,搬運轉載請註明出處,否則將追究版權責任。微訊號:a1018998632,交流qq群:859640274

最近學了近一個月半月的深度學習,所以想檢驗一下學習成果。正好畢設是影象處理APP的實現,所以就把快速風格遷移前饋神經網路通過Tensorflow for Android移植到了APP上面,作為濾鏡快速風格遷移的效果還挺不錯,就是速度有點慢。可能和現在Android端的深度學習還不支援gpu有關吧。

1.關於MyPhotoShop

這是一個圖片處理APP,裡面使用了Opencv、深度學習、MVVM、Databinding、RxJava、各種設計模式等等,在後面一段時間我會寫一系列部落格來一步步剖析這個專案,希望大家能多多關注。

1.效果

素描風格
梵高星夜風格

2.專案相關

3.缺點

  • 1.沒有元件化
  • 2.沒有混淆
  • 3.有些地方抽象不夠

2.深度學習和神經網路的基本概念

1.什麼是深度學習

  • 1.AI--》機器學習--》深度學習,前面三個概念是遞進的,簡單來說深度學習是機器學習的一種,深度學習就是利用機器來學習很多資料,而機器學習又是實現AI的一種方式。
  • 2.在深度學習中有兩個重要的東西:資料和神經網路。在深度學習中有兩個重要的過程:訓練和測試
    • 1.資料和網路:
      • 1.資料:我們想象一個簡單的圖片分類場景,我們有10000張已經被人工分好類的圖片,每張圖片都有一個正確的分類,比如貓、狗等等。
      • 2.網路:這裡的神經網路我們可以想象成一個函式,我們的輸入是一張圖片,輸出則是這張圖片在每個分類下面的分數。也就是一個分數的陣列。
    • 2.訓練和測試:
      • 1.訓練:在訓練的時候我們會將圖片集中的圖片一次次的輸入到神經網路裡面去,然後會一次次得到該圖片在每個分類下的分數,每當我們得出了一個分數陣列之後我們可以計算當前的神經網路損失值(當前的網路準確率越高損失值越低),有了損失值,我們的目標就是降低損失值。瞭解導數的同學都知道我們可以通過求導損失值函式得到讓損失值降低的梯度方向,然後反饋到神經網路中。就這樣一次次的迴圈,讓損失值降到最低。
      • 2.測試:當我們將神經網路訓練到了一個最佳的狀態,我們就可以將我們需要進行分類的圖片,輸入到神經網路中,得到最終神經網路對該圖片分類的結果。
    • 3.總結:深度學習到底是怎麼學習的呢?我們可以看見我們的訓練資料是經過人的處理的,那麼深度學習的過程就是將人的處理過程固化到我們的神經網路中,最終讓神經網路來代替人工處理的過程。
    • 4.上面只是介紹深度學習的基本流程,如果要更深入的瞭解可以看這篇部落格

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中執行一個已經訓練好的神經網路還是比較簡單的,只要知道了輸入輸出,就像執行一個普通的函式那麼簡單。至於如何去訓練一個神經網路,那就是另外的故事了,可以關注我的我學機器學習文集!裡面會持續更新我學習機器學習的心得和體會。

不販賣焦慮,也不標題黨。分享一些這個世界上有意思的事情。題材包括且不限於:科幻、科學、科技、網際網路、程式設計師、計算機程式設計。下面是我的微信公眾號:世界上有意思的事,乾貨多多等你來看。

世界上有意思的事

相關文章