文档扫描:深度神经网络在移动端的实践
隨著深度學(xué)習(xí)算法在圖像領(lǐng)域中的成功運用,學(xué)術(shù)界的目光重新回到神經(jīng)網(wǎng)絡(luò)上;而隨著 AlphaGo 在圍棋領(lǐng)域制造的大新聞,全科技界的目光都聚焦在“深度學(xué)習(xí)”、“神經(jīng)網(wǎng)絡(luò)”這些關(guān)鍵詞上。
與大眾的印象不完全一致的是,神經(jīng)網(wǎng)絡(luò)算法并不算是十分高深晦澀的算法;相對于機器學(xué)習(xí)中某一些數(shù)學(xué)味很強的算法來說,神經(jīng)網(wǎng)絡(luò)算法甚至可以算得上是“簡單粗暴”。
只是,在神經(jīng)網(wǎng)絡(luò)的訓(xùn)練過程中,以及算法的實際運用中,存在著許多困難,和一些經(jīng)驗,這些經(jīng)驗是比較有技巧性的。
有道云筆記不久前更新的文檔掃描功能中使用了神經(jīng)網(wǎng)絡(luò)算法。本文試圖以文檔掃描算法中所運用的神經(jīng)網(wǎng)絡(luò)算法為線索,聊一聊神經(jīng)網(wǎng)絡(luò)算法的原理,以及其在工程中的應(yīng)用。
背景篇
首先介紹一下什么是文檔掃描功能。文檔掃描功能希望能在用戶拍攝的照片中,識別出文檔所在的區(qū)域,進行拉伸(比例還原),識別出其中的文字,最終得到一張干凈的圖片或是一篇帶有格式的文字版筆記。實現(xiàn)這個功能需要以下這些步驟:
1.?識別文檔區(qū)域
將文檔從背景中找出來,確定文檔的四個角;
2. 拉伸文檔區(qū)域,還原寬高比
根據(jù)文檔四個角的坐標(biāo),根據(jù)透視原理,計算出文檔原始寬高比,并將文檔區(qū)域拉伸還原成矩形。這是所有步驟中唯一具有解析算法的步驟;
3. 色彩增強
根據(jù)文檔的類型,選擇不同的色彩增強方法,將文檔圖片的色彩變得干凈清潔;
4. 布局識別
理解文檔圖片的布局,找出文檔的文字部分;
5. OCR
將圖片形式的“文字”識別成可編碼的文字;
6. 生成筆記
根據(jù)文檔圖片的布局,從 OCR 的結(jié)果中生成帶有格式的筆記。
在上述這些步驟中,“拉伸文檔區(qū)域”和“生成筆記”是有解析算法或明確規(guī)則的,不需要機器學(xué)習(xí)處理。剩下的步驟中都含有機器學(xué)習(xí)算法。其中“文檔區(qū)域識別”和“OCR”這兩個步驟我們是采用深度神經(jīng)網(wǎng)絡(luò)算法來完成的。
之所以在這兩個步驟選擇深度神經(jīng)網(wǎng)絡(luò)算法,是考慮到其他算法很難滿足我們的需求:
· 場景復(fù)雜,淺層學(xué)習(xí)很難很好的學(xué)習(xí)推廣;
同時,深度神經(jīng)網(wǎng)絡(luò)的一些難點在這兩個步驟中相對不那么困難。
· ?屬于深度神經(jīng)網(wǎng)絡(luò)算法所擅長的圖像和時序領(lǐng)域;
· ?能夠獲取到大量的數(shù)據(jù)。能夠?qū)@些數(shù)據(jù)進行明確的標(biāo)注。
接下來的內(nèi)容中,我們將展開講講“文檔區(qū)域識別”步驟中的神經(jīng)網(wǎng)絡(luò)算法。
算法篇
文檔區(qū)域識別中使用的神經(jīng)網(wǎng)絡(luò)算法主要是全卷積網(wǎng)絡(luò)(FCN)[1]。在介紹 FCN 前,首先簡單介紹一下 FCN 的基礎(chǔ),卷積神經(jīng)網(wǎng)絡(luò)(這里假設(shè)讀者對人工神經(jīng)網(wǎng)絡(luò)有最基本的了解)。
卷積神經(jīng)網(wǎng)絡(luò)(CNN, Convolutional Neural Networks)
卷積神經(jīng)網(wǎng)絡(luò)(CNN)早在 1962 年就被提出[2],而目前最廣泛應(yīng)用的結(jié)構(gòu)大概是 LeCun 在 1998 年提出的[3]。
CNN 和普通神經(jīng)網(wǎng)絡(luò)一樣,由輸入、輸出層和若干隱層組成。CNN 的每一層并不是一維的,而是有(長, 寬, 通道數(shù))三個維度,例如輸入層為一張 rgb 圖片,則其輸入層三個維度分別是(圖片高度, 圖片寬度, 3)。
與普通神經(jīng)網(wǎng)絡(luò)相比,CNN 有如下特點:
1. 第 n 層的某個節(jié)點并不和第 n-1 層的所有節(jié)點相關(guān),只和它空間位置附近的(n-1層)節(jié)點相關(guān);
2. 同一層中,所有節(jié)點共享權(quán)值;
3. 每隔若干層會有一個池化(pool)層,其功能是按比例縮小這一層的長和寬(通常是減半)。常用的 pool 方法有局部極大值(Max)和局部均值(Mean)兩種。
通過加入若干 pool 層,CNN 中隱層的長和寬不斷縮小。當(dāng)長寬縮小到一定程度(通常是個位數(shù))的時候,CNN 在頂部連接上一個傳統(tǒng)的全連接(Fully connected)神經(jīng)網(wǎng)絡(luò),整個網(wǎng)絡(luò)結(jié)構(gòu)就搭建完成了。
CNN 之所以能夠有效,在于它利用了圖像中的一些約束。
特點 1 對應(yīng)著圖像的局域相關(guān)性(圖像上右上角某點跟遠處左下角某點關(guān)系不大);特點 2 對應(yīng)著圖像的平移不變性(圖像右上角的形狀,移動到左下角仍然是那個形狀);特點 3 對應(yīng)著圖像的放縮不變性(圖像縮放后,信息丟失的很少)。
這些約束的加入,就好比物理中”動量守恒定理“這類發(fā)現(xiàn)。守恒定理能讓物體的運動可預(yù)測,而約束的加入能讓識別過程變得可控,對訓(xùn)練數(shù)據(jù)的需求降低,更不容易出現(xiàn)過擬合。
全卷積網(wǎng)絡(luò)(FCN, Fully Convolutional Networks)
全卷積網(wǎng)絡(luò) (FCN) 是 CNN 基礎(chǔ)上發(fā)展起來的算法。與 CNN 不同,FCN 要解決這樣的問題:圖像的識別目標(biāo)不是圖像級的標(biāo)簽,而是像素級的標(biāo)簽。例如:
1.?圖像分割需要將圖像根據(jù)語義分割成若干類別,其中每一個像素都對應(yīng)著一個分類結(jié)果;
2.?邊緣檢測需要將圖像中的邊緣部分和非邊緣部分分隔開來,其中每一個像素都對應(yīng)著“邊緣”或“非邊緣”(我們面對的就屬于這類問題)。
3.?視頻分割將圖像分割用在連續(xù)的視頻圖像中。
在 CNN 中,pool 層讓隱層的長寬縮小,而 FCN 面對的是完整長寬的標(biāo)簽,如何處理這對矛盾呢?
一個辦法是不使用 pool 層,讓每一個隱層的長寬都等于完整的長寬。
這樣做的缺點是,一來計算量相當(dāng)大,尤其是當(dāng)運算進行到 CNN 的較高層,通道數(shù)達到幾百上千的時候;二來不使用 pool 層,卷積就始終是在局域進行,這樣識別的結(jié)果沒有利用到全局信息。
另一個辦法是轉(zhuǎn)置卷積(convolution transpose),可以理解為反向操作的 pool 層,或者上采樣層,將隱層通過插值放縮回原來的長寬。這正是 FCN 采用的辦法。
當(dāng)然,由于 CNN 的最后一個隱層的長寬很小,基本上只有全局信息,如果只對該隱層進行上采樣,則局部細(xì)節(jié)就都丟失了。
為此,FCN 會對 CNN 中間的幾個隱層進行同樣的上采樣,由于中間層放縮的程度較低,保留了較多的局部細(xì)節(jié),因而上采樣的結(jié)果也會包含較多的局域信息。
最后,將幾個上采樣的結(jié)果綜合起來作為輸出,這樣就能比較好的平衡全局和局域信息。
整個 FCN 的結(jié)構(gòu)如上圖所示。FCN 去掉了 CNN 在頂部連接的全連接層,在每個轉(zhuǎn)置卷積層之前都有一個分類器,將分類器的輸出上采樣(轉(zhuǎn)置卷積),然后相加。
上圖是我們實驗中真實產(chǎn)生的上采樣結(jié)果。可以看到,層級較低的隱層保留了很多圖片細(xì)節(jié),而層級較高的隱層對全局分布理解的比較好。將二者綜合起來,得到了既包含全局信息,又沒有丟失局域信息的結(jié)果。
轉(zhuǎn)置卷積(convolution transpose)
上文中出現(xiàn)的“轉(zhuǎn)置卷積”是怎樣實現(xiàn)的呢?顧名思義,轉(zhuǎn)置卷積也是一種卷積操作,只不過是將 CNN 中的卷積操作的 Input 和 Output 的大小反轉(zhuǎn)了過來。
https://github.com/vdumoulin/conv_arithmetic?
以上項目中提供了一系列轉(zhuǎn)置卷積的圖示,不過我個人認(rèn)為更符合原意的轉(zhuǎn)置卷積的圖示如下圖:
?
與 conv_arithmetric 提供的圖示對比,可以看出上圖只是卷積示意圖的上下翻轉(zhuǎn)。在實際運算中,Input 層的某個節(jié)點數(shù)值會(以卷積核為權(quán)重)加權(quán)相加到與該節(jié)點相關(guān)的每一個 Output 層節(jié)點上。
從維度上來看,如果記卷積核的高、寬為 H 和 W,Input 層的 channel 數(shù)為 C,Output 層的 channel 數(shù)為 O,那么一次正向卷積的輸入節(jié)點數(shù)為 H * W * C,輸出節(jié)點數(shù)為 O;而一次轉(zhuǎn)置卷積運算的輸入節(jié)點數(shù)為 C ,輸出節(jié)點數(shù)為 H * W * O。
改進的 cross entropy 損失函數(shù)
在邊緣識別問題中,每一個像素都對應(yīng)著“邊緣-非邊緣”中的某一類。于是,我們可以認(rèn)為每一個像素都是一個訓(xùn)練樣本。
這會帶來一個問題:通常圖片中的邊緣要遠少于非邊緣,于是兩類樣本的數(shù)量懸殊。在模式識別問題中,類別不平衡會造成很多不可控的結(jié)果,是要極力避免的。
通常面對這種情況,我們會采用對少樣本類別進行重復(fù)采樣(過采樣),或是基于原樣本的空間分布產(chǎn)生人工數(shù)據(jù)。然而在本問題中,由于同一張圖中包含很多樣本,這兩種常用的方法都不能進行。該怎么解決樣本數(shù)量懸殊問題呢?
2015 年 ICCV 上的一篇論文[4]提出了名為 HED 的邊緣識別模型,試著用改變損失函數(shù)(Loss Function)的定義來解決這個問題。我們的算法中也采用了這種方法。
首先我們概述一下 CNN 常用的 cross entropy 損失函數(shù)。在二分類問題里,cross entropy 的定義如下:
這里 l 為損失值,n 為樣本數(shù),k 表示第幾個樣本,Q 表示標(biāo)簽值,取值為 0 或者 1,p 為分類器計算出來的"該樣本屬于類別 1 "的概率,在 0 到 1 之間。
這個函數(shù)雖然看起來復(fù)雜,但如果對它取指數(shù)(L=exp(-l)),會發(fā)現(xiàn)這是全部樣本均預(yù)測正確的概率。比如樣本集的標(biāo)簽值分別為 (1, 1, 0, 1, 1, 0, ...),則:
這里 L 是似然函數(shù),也就是全部樣本均預(yù)測正確的概率。
HED 使用了加權(quán)的 cross entropy 函數(shù)。例如,當(dāng)標(biāo)簽 0 對應(yīng)的樣本極少時,加權(quán) cross entropy 函數(shù)定義為:
這里 W 為權(quán)重,需要大于 1。不妨設(shè) W = 2,此時考慮似然函數(shù):
可見類別為 0 的樣本在似然函數(shù)中重復(fù)出現(xiàn)了,比重因此而增加。通過這種辦法,我們雖然不能實際將少樣本類別的樣本數(shù)目擴大,卻通過修改損失函數(shù)達到了基本等價的效果。
數(shù)據(jù)篇
文檔區(qū)域識別中用到的神經(jīng)網(wǎng)絡(luò)算法就介紹到這里了,接下來聊一聊我們?yōu)橛?xùn)練這個神經(jīng)網(wǎng)絡(luò)所構(gòu)建的數(shù)據(jù)集。
數(shù)據(jù)篩選
為了訓(xùn)練神經(jīng)網(wǎng)絡(luò)模型,我們標(biāo)注了樣本容量為五萬左右的數(shù)據(jù)集。然而這些數(shù)據(jù)集中存在大量的壞數(shù)據(jù),需要對數(shù)據(jù)進行進一步篩選。
五萬左右的數(shù)據(jù)集,只憑人工來進行篩選成本太高了。好在根據(jù)網(wǎng)絡(luò)的自由度等一些經(jīng)驗判斷,我們的網(wǎng)絡(luò)對數(shù)據(jù)集的大小要求尚沒有那么高,數(shù)據(jù)集還算比較富足,可以允許一部分好的數(shù)據(jù)被錯篩掉。
基于這一前提,我們?nèi)斯?biāo)注了一個小訓(xùn)練集(500 張),訓(xùn)練了一個 SVM 分類器來自動篩選數(shù)據(jù)。這個分類器只能判斷圖片中是否含有完整的文檔,且分類效果并不特別強。
不過,我們有選擇性的強調(diào)了分類器分類的準(zhǔn)確率,而對其召回率要求不高。換而言之,這個分類器可以接受把含有文檔的圖片錯分成了不含文檔的圖片,但不能接受把不含文檔的圖片分進了含有文檔的圖片這一類中。
依靠這個分類器,我們將五萬左右的數(shù)據(jù)集篩選得到了一個九千左右的較小數(shù)據(jù)集。再加上人工篩選,最終剩下容量為八千左右的,質(zhì)量有保證的數(shù)據(jù)集。
實現(xiàn)篇
在模型訓(xùn)練中,我們使用 tensorflow 框架[5]進行模型訓(xùn)練。我們的最終目標(biāo)是在移動端(手機端)實現(xiàn)文檔區(qū)域識別功能,而移動端與桌面端存在著一些區(qū)別:
1. 移動端的運算能力全方位的弱于桌面端;
2. 帶寬和功耗端限制,決定了移動端的顯卡尤其弱于桌面端的獨顯;
3. 移動端有 ios 和 Android 兩個陣營,它們對密集運算的優(yōu)化 API 各不相同,代碼很難通用;
4. 移動端對文件體積敏感。
這些區(qū)別使得我們不能直接將模型移植到移動端,而需要對它們做一些優(yōu)化,保證其運行效率。優(yōu)化的思路大致有兩種:
1. 選擇合適的神經(jīng)網(wǎng)絡(luò)框架,盡可能用上芯片的加速技術(shù);
2. 壓縮模型,在不損失精度的前提下減小模型的計算開銷和文件體積。
神經(jīng)網(wǎng)絡(luò)框架的選擇
目前比較流行的神經(jīng)網(wǎng)絡(luò)框架包括 tensorflow, caffe[6], mxnet[7]?等,它們大多數(shù)都有相應(yīng)的移動端框架。所以直接使用這些移動端框架是最方便的選擇。
例如我們使用 tensorflow 框架進行模型訓(xùn)練,那么直接使用移動端 tensorflow 框架,就能省去模型轉(zhuǎn)換的麻煩。
有的時候,我們可能不需要一個大而全的神經(jīng)網(wǎng)絡(luò)框架,或者對運行效率要求特別高。此時我們可以考慮一個底層一些的框架,在此基礎(chǔ)上實現(xiàn)自己的需求。
這方面的例子有 Eigen[8],一個常用的矩陣運算庫;NNPACK[9],效率很高的神經(jīng)網(wǎng)絡(luò)底層庫,等等。如果代碼中已經(jīng)集成了 OpenCV[10],也可以考慮用其中的運算 API。
如果對運行效率要求很高,也可以考慮使用移動端的異構(gòu)計算框架,將除 CPU 以外的 GPU、DSP 的運算能力也加入進來。
這方面可以考慮的框架有 ios 端的 metal[11],跨平臺的 OpenGL[12]?和 Vulkan[13],Android 端的 renderscript[14]。
模型壓縮
模型壓縮最簡單的方法就是去調(diào)節(jié)網(wǎng)絡(luò)模型中各個可調(diào)的超參數(shù),這里的超參數(shù)的例子有:網(wǎng)絡(luò)總層數(shù)、每一層的 channel 數(shù)、每一個卷積的 kernel 寬度 等等。
在一開始訓(xùn)練的時候,我們會選擇有一定冗余的超參數(shù)去訓(xùn)練,確保不會因為某個超參數(shù)太小而成為網(wǎng)絡(luò)效果的瓶頸。
在模型壓縮的時候,則可以把這些冗余“擠掉”,即在不明顯降低識別準(zhǔn)確率的前提下,逐步嘗試調(diào)小某個超參數(shù)。
在調(diào)節(jié)的過程中,我們發(fā)現(xiàn)網(wǎng)絡(luò)總層數(shù)對識別效果的影響較大;相對而言,每一層的 channel 數(shù)的減小對識別效果的影響不大。
除了簡單的調(diào)節(jié)超參數(shù)外,還有一些特別為移動端設(shè)計的模型結(jié)構(gòu),采用這些模型結(jié)構(gòu)能顯著的壓縮模型。這方面的例子有 SVD Network[15], SqueezeNet[16], Mobilenets[17]等,這里就不細(xì)說了。
最終效果
經(jīng)過神經(jīng)網(wǎng)絡(luò)框架定制、模型壓縮后,我們的模型大小被壓縮到 1M 左右,在性能主流的手機(iphone 6, 小米 4 或配置更好的手機)上能達到 100ms 以內(nèi)識別一張圖片的速度,且識別精度基本沒有受到影響。應(yīng)該說移植是很成功的。
總結(jié)
在兩三年之前,神經(jīng)網(wǎng)絡(luò)算法在大家的眼里只適用于運算能力極強的服務(wù)器,似乎跟手機沒有什么關(guān)聯(lián)。
然而在近兩三年,出現(xiàn)了一些新的趨勢:一是隨著神經(jīng)網(wǎng)絡(luò)算法的成熟,一部分學(xué)者將研究興趣放在了壓縮神經(jīng)網(wǎng)絡(luò)的計算開銷上,神經(jīng)網(wǎng)絡(luò)模型可以得到壓縮;二是手機芯片的運算能力飛速發(fā)展,尤其是 GPU,DSP 運算能力的發(fā)展。伴隨這一降一升,手機也能夠得著神經(jīng)網(wǎng)絡(luò)的運算需求了。
“基于神經(jīng)網(wǎng)絡(luò)的文檔掃描”功能得以實現(xiàn),實在是踩在了無數(shù)前人的肩膀上完成的。從這個角度來說,我們這一代的研發(fā)人員是幸運的,能夠?qū)崿F(xiàn)一些我們過去不敢想象的東西,未來還能實現(xiàn)更多我們今天不能想象的東西。
參考文獻
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.
關(guān)于PaperWeekly
PaperWeekly 是一個推薦、解讀、討論、報道人工智能前沿論文成果的學(xué)術(shù)平臺。如果你研究或從事 AI 領(lǐng)域,歡迎在公眾號后臺點擊「交流群」,小助手將把你帶入 PaperWeekly 的交流群里。
總結(jié)
以上是生活随笔為你收集整理的文档扫描:深度神经网络在移动端的实践的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: SamplePairing:针对图像处理
- 下一篇: 三招武林绝学带你玩转「强化学习」