歡迎光臨
每天分享高質量文章

檔案掃描:深度神經網路在移動端的實踐

隨著深度學習演演算法在影象領域中的成功運用,學術界的目光重新回到神經網路上;而隨著 AlphaGo 在圍棋領域製造的大新聞,全科技界的目光都聚焦在“深度學習”、“神經網路”這些關鍵詞上。


與大眾的印象不完全一致的是,神經網路演演算法並不算是十分高深晦澀的演演算法;相對於機器學習中某一些數學味很強的演演算法來說,神經網路演演算法甚至可以算得上是“簡單粗暴”。


只是,在神經網路的訓練過程中,以及演演算法的實際運用中,存在著許多困難,和一些經驗,這些經驗是比較有技巧性的。


有道雲筆記不久前更新的檔案掃描功能中使用了神經網路演演算法。本文試圖以檔案掃描演演算法中所運用的神經網路演演算法為線索,聊一聊神經網路演演算法的原理,以及其在工程中的應用。


背景篇


首先介紹一下什麼是檔案掃描功能。檔案掃描功能希望能在使用者拍攝的照片中,識別出文件所在的區域,進行拉伸(比例還原),識別出其中的文字,最終得到一張乾凈的圖片或是一篇帶有格式的文字版筆記。實現這個功能需要以下這些步驟:


1. 識別檔案區域


將檔案從背景中找出來,確定檔案的四個角;


2. 拉伸檔案區域,還原寬高比


根據檔案四個角的坐標,根據透視原理,計算出檔案原始寬高比,並將檔案區域拉伸還原成矩形。這是所有步驟中唯一具有解析演演算法的步驟;


3. 色彩增強


根據檔案的型別,選擇不同的色彩增強方法,將檔案圖片的色彩變得乾凈清潔;


4. 佈局識別


理解檔案圖片的佈局,找出檔案的文字部分;


5. OCR


將圖片形式的“文字”識別成可編碼的文字;


6. 生成筆記


根據檔案圖片的佈局,從 OCR 的結果中生成帶有格式的筆記。



在上述這些步驟中,“拉伸檔案區域”和“生成筆記”是有解析演演算法或明確規則的,不需要機器學習處理。剩下的步驟中都含有機器學習演演算法。其中“檔案區域識別”和“OCR”這兩個步驟我們是採用深度神經網路演演算法來完成的。


之所以在這兩個步驟選擇深度神經網路演演算法,是考慮到其他演演算法很難滿足我們的需求:


· 場景複雜,淺層學習很難很好的學習推廣;


同時,深度神經網路的一些難點在這兩個步驟中相對不那麼困難。


·  屬於深度神經網路演演算法所擅長的影象和時序領域;

·  能夠獲取到大量的資料。能夠對這些資料進行明確的標註。


接下來的內容中,我們將展開講講“檔案區域識別”步驟中的神經網路演演算法。


演演算法篇


檔案區域識別中使用的神經網路演演算法主要是全摺積網路(FCN)[1]。在介紹 FCN 前,首先簡單介紹一下 FCN 的基礎,摺積神經網路(這裡假設讀者對人工神經網路有最基本的瞭解)。


摺積神經網路(CNN, Convolutional Neural Networks)


摺積神經網路(CNN)早在 1962 年就被提出[2],而目前最廣泛應用的結構大概是 LeCun 在 1998 年提出的[3]。


CNN 和普通神經網路一樣,由輸入、輸出層和若干隱層組成。CNN 的每一層並不是一維的,而是有(長, 寬, 通道數)三個維度,例如輸入層為一張 rgb 圖片,則其輸入層三個維度分別是(圖片高度, 圖片寬度, 3)。


與普通神經網路相比,CNN 有如下特點:


1. 第 n 層的某個節點並不和第 n-1 層的所有節點相關,只和它空間位置附近的(n-1層)節點相關;


2. 同一層中,所有節點共享權值;


3. 每隔若干層會有一個池化(pool)層,其功能是按比例縮小這一層的長和寬(通常是減半)。常用的 pool 方法有區域性極大值(Max)和區域性均值(Mean)兩種。


透過加入若干 pool 層,CNN 中隱層的長和寬不斷縮小。當長寬縮小到一定程度(通常是個位數)的時候,CNN 在頂部連線上一個傳統的全連線(Fully connected)神經網路,整個網路結構就搭建完成了。



CNN 之所以能夠有效,在於它利用了影象中的一些約束。


特點 1 對應著影象的局域相關性(影象上右上角某點跟遠處左下角某點關係不大);特點 2 對應著影象的平移不變性(影象右上角的形狀,移動到左下角仍然是那個形狀);特點 3 對應著影象的放縮不變性(影象縮放後,資訊丟失的很少)。


這些約束的加入,就好比物理中”動量守恆定理“這類發現。守恆定理能讓物體的運動可預測,而約束的加入能讓識別過程變得可控,對訓練資料的需求降低,更不容易出現過擬合。


全摺積網路(FCN, Fully Convolutional Networks)



全摺積網路 (FCN) 是 CNN 基礎上發展起來的演演算法。與 CNN 不同,FCN 要解決這樣的問題:影象的識別標的不是影象級的標簽,而是畫素級的標簽。例如:


1. 影象分割需要將影象根據語意分割成若干類別,其中每一個畫素都對應著一個分類結果;


2. 邊緣檢測需要將影象中的邊緣部分和非邊緣部分分隔開來,其中每一個畫素都對應著“邊緣”或“非邊緣”(我們面對的就屬於這類問題)。


3. 影片分割將影象分割用在連續的影片影象中。

在 CNN 中,pool 層讓隱層的長寬縮小,而 FCN 面對的是完整長寬的標簽,如何處理這對矛盾呢?


一個辦法是不使用 pool 層,讓每一個隱層的長寬都等於完整的長寬。


這樣做的缺點是,一來計算量相當大,尤其是當運算進行到 CNN 的較高層,通道數達到幾百上千的時候;二來不使用 pool 層,摺積就始終是在局域進行,這樣識別的結果沒有利用到全域性資訊。


另一個辦法是轉置摺積(convolution transpose),可以理解為反向操作的 pool 層,或者上取樣層,將隱層透過插值放縮回原來的長寬。這正是 FCN 採用的辦法。


當然,由於 CNN 的最後一個隱層的長寬很小,基本上只有全域性資訊,如果只對該隱層進行上取樣,則區域性細節就都丟失了。


為此,FCN 會對 CNN 中間的幾個隱層進行同樣的上取樣,由於中間層放縮的程度較低,保留了較多的區域性細節,因而上取樣的結果也會包含較多的局域資訊。


最後,將幾個上取樣的結果綜合起來作為輸出,這樣就能比較好的平衡全域性和局域資訊。



整個 FCN 的結構如上圖所示。FCN 去掉了 CNN 在頂部連線的全連線層,在每個轉置摺積層之前都有一個分類器,將分類器的輸出上取樣(轉置摺積),然後相加。



上圖是我們實驗中真實產生的上取樣結果。可以看到,層級較低的隱層保留了很多圖片細節,而層級較高的隱層對全域性分佈理解的比較好。將二者綜合起來,得到了既包含全域性資訊,又沒有丟失局域資訊的結果。


轉置摺積(convolution transpose)


上文中出現的“轉置摺積”是怎樣實現的呢?顧名思義,轉置摺積也是一種摺積操作,只不過是將 CNN 中的摺積操作的 Input 和 Output 的大小反轉了過來。


https://github.com/vdumoulin/conv_arithmetic 


以上專案中提供了一系列轉置摺積的圖示,不過我個人認為更符合原意的轉置摺積的圖示如下圖:

 



與 conv_arithmetric 提供的圖示對比,可以看出上圖只是摺積示意圖的上下翻轉。在實際運算中,Input 層的某個節點數值會(以摺積核為權重)加權相加到與該節點相關的每一個 Output 層節點上。


從維度上來看,如果記摺積核的高、寬為 H 和 W,Input 層的 channel 數為 C,Output 層的 channel 數為 O,那麼一次正向摺積的輸入節點數為 H * W * C,輸出節點數為 O;而一次轉置摺積運算的輸入節點數為 C ,輸出節點數為 H * W * O。


改進的 cross entropy 損失函式


在邊緣識別問題中,每一個畫素都對應著“邊緣-非邊緣”中的某一類。於是,我們可以認為每一個畫素都是一個訓練樣本。


這會帶來一個問題:通常圖片中的邊緣要遠少於非邊緣,於是兩類樣本的數量懸殊。在樣式識別問題中,類別不平衡會造成很多不可控的結果,是要極力避免的。


通常面對這種情況,我們會採用對少樣本類別進行重覆取樣(過取樣),或是基於原樣本的空間分佈產生人工資料。然而在本問題中,由於同一張圖中包含很多樣本,這兩種常用的方法都不能進行。該怎麼解決樣本數量懸殊問題呢?


2015 年 ICCV 上的一篇論文[4]提出了名為 HED 的邊緣識別模型,試著用改變損失函式(Loss Function)的定義來解決這個問題。我們的演演算法中也採用了這種方法。


首先我們概述一下 CNN 常用的 cross entropy 損失函式。在二分類問題裡,cross entropy 的定義如下:


這裡 l 為損失值,n 為樣本數,k 表示第幾個樣本,Q 表示標簽值,取值為 0 或者 1,p 為分類器計算出來的”該樣本屬於類別 1 “的機率,在 0 到 1 之間。


這個函式雖然看起來複雜,但如果對它取指數(L=exp(-l)),會發現這是全部樣本均預測正確的機率。比如樣本集的標簽值分別為 (1, 1, 0, 1, 1, 0, …),則:


這裡 L 是似然函式,也就是全部樣本均預測正確的機率。


HED 使用了加權的 cross entropy 函式。例如,當標簽 0 對應的樣本極少時,加權 cross entropy 函式定義為:


這裡 W 為權重,需要大於 1。不妨設 W = 2,此時考慮似然函式:



可見類別為 0 的樣本在似然函式中重覆出現了,比重因此而增加。透過這種辦法,我們雖然不能實際將少樣本類別的樣本數目擴大,卻透過修改損失函式達到了基本等價的效果。


資料篇


檔案區域識別中用到的神經網路演演算法就介紹到這裡了,接下來聊一聊我們為訓練這個神經網路所構建的資料集。


資料篩選


為了訓練神經網路模型,我們標註了樣本容量為五萬左右的資料集。然而這些資料集中存在大量的壞資料,需要對資料進行進一步篩選。


五萬左右的資料集,只憑人工來進行篩選成本太高了。好在根據網路的自由度等一些經驗判斷,我們的網路對資料集的大小要求尚沒有那麼高,資料集還算比較富足,可以允許一部分好的資料被錯篩掉。


基於這一前提,我們人工標註了一個小訓練集(500 張),訓練了一個 SVM 分類器來自動篩選資料。這個分類器只能判斷圖片中是否含有完整的檔案,且分類效果並不特別強。


不過,我們有選擇性的強調了分類器分類的準確率,而對其召回率要求不高。換而言之,這個分類器可以接受把含有檔案的圖片錯分成了不含檔案的圖片,但不能接受把不含檔案的圖片分進了含有檔案的圖片這一類中。


依靠這個分類器,我們將五萬左右的資料集篩選得到了一個九千左右的較小資料集。再加上人工篩選,最終剩下容量為八千左右的,質量有保證的資料集。


實現篇


在模型訓練中,我們使用 tensorflow 框架[5]進行模型訓練。我們的最終標的是在移動端(手機端)實現檔案區域識別功能,而移動端與桌面端存在著一些區別:


1. 移動端的運算能力全方位的弱於桌面端;


2. 頻寬和功耗端限制,決定了移動端的顯示卡尤其弱於桌面端的獨顯;


3. 移動端有 ios 和 Android 兩個陣營,它們對密集運算的最佳化 API 各不相同,程式碼很難通用;


4. 移動端對檔案體積敏感。


這些區別使得我們不能直接將模型移植到移動端,而需要對它們做一些最佳化,保證其執行效率。最佳化的思路大致有兩種:


1. 選擇合適的神經網路框架,盡可能用上晶片的加速技術;

2. 壓縮模型,在不損失精度的前提下減小模型的計算開銷和檔案體積


神經網路框架的選擇


目前比較流行的神經網路框架包括 tensorflow, caffe[6], mxnet[7] 等,它們大多數都有相應的移動端框架。所以直接使用這些移動端框架是最方便的選擇。


例如我們使用 tensorflow 框架進行模型訓練,那麼直接使用移動端 tensorflow 框架,就能省去模型轉換的麻煩。


有的時候,我們可能不需要一個大而全的神經網路框架,或者對執行效率要求特別高。此時我們可以考慮一個底層一些的框架,在此基礎上實現自己的需求。


這方面的例子有 Eigen[8],一個常用的矩陣運算庫;NNPACK[9],效率很高的神經網路底層庫,等等。如果程式碼中已經集成了 OpenCV[10],也可以考慮用其中的運算 API。


如果對執行效率要求很高,也可以考慮使用移動端的異構計算框架,將除 CPU 以外的 GPU、DSP 的運算能力也加入進來。


這方面可以考慮的框架有 ios 端的 metal[11],跨平臺的 OpenGL[12] 和 Vulkan[13],Android 端的 renderscript[14]。



模型壓縮


模型壓縮最簡單的方法就是去調節網路模型中各個可調的超引數,這裡的超引數的例子有:網路總層數、每一層的 channel 數、每一個摺積的 kernel 寬度 等等。


在一開始訓練的時候,我們會選擇有一定冗餘的超引數去訓練,確保不會因為某個超引數太小而成為網路效果的瓶頸。


在模型壓縮的時候,則可以把這些冗餘“擠掉”,即在不明顯降低識別準確率的前提下,逐步嘗試調小某個超引數。


在調節的過程中,我們發現網路總層數對識別效果的影響較大;相對而言,每一層的 channel 數的減小對識別效果的影響不大。


除了簡單的調節超引數外,還有一些特別為移動端設計的模型結構,採用這些模型結構能顯著的壓縮模型。這方面的例子有 SVD Network[15], SqueezeNet[16], Mobilenets[17]等,這裡就不細說了。


最終效果


經過神經網路框架定製、模型壓縮後,我們的模型大小被壓縮到 1M 左右,在效能主流的手機(iphone 6, 小米 4 或配置更好的手機)上能達到 100ms 以內識別一張圖片的速度,且識別精度基本沒有受到影響。應該說移植是很成功的。


總結


在兩三年之前,神經網路演演算法在大家的眼裡只適用於運算能力極強的伺服器,似乎跟手機沒有什麼關聯。


然而在近兩三年,出現了一些新的趨勢:一是隨著神經網路演演算法的成熟,一部分學者將研究興趣放在了壓縮神經網路的計算開銷上,神經網路模型可以得到壓縮;二是手機晶片的運算能力飛速發展,尤其是 GPU,DSP 運算能力的發展。伴隨這一降一升,手機也能夠得著神經網路的運算需求了。


“基於神經網路的檔案掃描”功能得以實現,實在是踩在了無數前人的肩膀上完成的。從這個角度來說,我們這一代的研發人員是幸運的,能夠實現一些我們過去不敢想象的東西,未來還能實現更多我們今天不能想象的東西。

參考文獻



1. Long, J., Shelhamer, E., & Darrell, T. (2015). Fully convolutional networks for semantic segmentation. In Proceedings of the IEEE Conference on Computer Vision and Pattern Recognition (pp. 3431-3440).

2. Hubel, D. H., & Wiesel, T. N. (1962). Receptive fields, binocular interaction and functional architecture in the cat’s visual cortex. The Journal of physiology, 160(1), 106-154.

3. LeCun, Y., Bottou, L., Bengio, Y., & Haffner, P. (1998). Gradient-based learning applied to document recognition. Proceedings of the IEEE, 86(11), 2278-2324.

4. Xie, S., & Tu, Z. (2015). Holistically-nested edge detection. In Proceedings of the IEEE International Conference on Computer Vision (pp. 1395-1403).

5. https://www.tensorflow.org/

6. http://caffe.berkeleyvision.org/

7. http://mxnet.io/

8. http://eigen.tuxfamily.org/index.php?title=Main_Page

9. https://github.com/Maratyszcza/NNPACK

10. http://opencv.org/

11. https://developer.apple.com/metal/

12. https://www.opengl.org/

13. https://www.khronos.org/vulkan/

14. https://developer.android.com/guide/topics/renderscript/compute.html

15. Denton, E. L., Zaremba, W., Bruna, J., LeCun, Y., & Fergus, R. (2014). Exploiting linear structure within convolutional networks for efficient evaluation. In Advances in Neural Information Processing Systems (pp. 1269-1277).

16. Iandola, F. N., Han, S., Moskewicz, M. W., Ashraf, K., Dally, W. J., & Keutzer, K. (2016). SqueezeNet: AlexNet-level accuracy with 50x fewer parameters and< 0.5 MB model size. arXiv preprint arXiv:1602.07360.

17. Howard, A. G., Zhu, M., Chen, B., Kalenichenko, D., Wang, W., Weyand, T., … & Adam, H. (2017). Mobilenets: Efficient convolutional neural networks for mobile vision applications. arXiv preprint arXiv:1704.04861.


關於PaperWeekly


PaperWeekly 是一個推薦、解讀、討論、報道人工智慧前沿論文成果的學術平臺。如果你研究或從事 AI 領域,歡迎在公眾號後臺點選「交流群」,小助手將把你帶入 PaperWeekly 的交流群裡。


贊(0)

分享創造快樂