天天看點

OCR性能優化:從神經網絡到橡皮泥

摘要:在這個算力還可以的時代,我們的研究人員一方面緻力于不斷地去研究各中不同的場景中的的通用網絡,一方面緻力于優化神經網絡的學習方式,這些都是在試圖化減少AI需要的算力資源。

本文分享自華為雲社群《OCR性能優化系列(二):從神經網絡到橡皮泥》,原文作者:HW007 。

OCR是指對圖檔中的印刷體文字進行識别,最近在做OCR模型的性能優化,用 Cuda C 将基于TensorFlow 編寫的OCR網絡重寫了一遍,最終做到了5倍的性能提升。通過這次優化工作對OCR網絡的通用網絡結構和相關的優化方法有較深的認識,計劃在此通過系列博文記錄下來,也作為對自己最近工作的一個總結和學習筆記。在第一篇《OCR性能優化系列(一):BiLSTM網絡結構概覽》中,從動機的角度來推演下基于Seq2Seq結構的OCR網絡是如何一步步搭建起來的。接下來我們講從神經網絡到橡皮泥。

 1. 深扒CNN:也談機器學習的本質

現在,從OCR性能優化系列(一)中的圖1左下角的輸入開始,串一遍圖一的流程。首先是輸入27張待識别的文字片段圖檔,每張圖檔的大小為32*132。這些圖檔會經過一個CNN網絡進行編碼,輸出32個27*384的初步編碼矩陣。如下圖所示:

OCR性能優化:從神經網絡到橡皮泥

值得注意的是,在這步操作中出現了次元次序的調整,即輸入由27*(32*132)變成了 27*(384),你可以了解為把尺寸為32*132的圖檔拉長拍扁成一行(1*4224),然後再進行降維為 1*384了,類似于上文優化政策一中做計算量優化時把1024降到128的例子。怎麼做這個從 27*4224到27*384的降維呢?最簡單粗暴的方法就是上面的Y=AX+B模型,直接給27*4224乘以一個4224*384的矩陣A,矩陣A是通過喂資料訓練得到的。很明顯,對同樣的X,不同的A得到的Y也不一樣,而從4224到384這個次元降得又有點狠。于是,學者們便祭出了群毆大法,一個A不行,那就上多個A吧。于是在這裡便祭出了32個A,這個32便是後面的LSTM網絡的序列長度,與輸入圖檔的寬度132成比例。當輸入圖檔的寬度變成260時,就需要64個A了。

也許有人會問在CNN中看不到你說的32個A啊?的确,那隻是我對CNN網絡功能的抽象,重點在于讓大家對CNN編碼過程中次元的變化及其下一層LSTM網絡的序列長度有個形象的認識,知道LSTM的序列長度其實是“降維器”的數量。如果你比較機智的話,你應該發現我連“降維”都說錯了,因為如果把32個“降維器”輸出的結果拼一起的話是32*384=12288,遠大于4224,資料經過CNN網絡後,次元不但沒有減少,反而增加了!其實這個東西比較正式的叫法是“編碼器”或“解碼器”,“降維器”是我本文中為了形象點自創的,不管叫貓還是叫咪,我希望你能記住,他的本質就是那個系數矩陣A而已。

現在我們還是沿着32個A這個思路走下去,經過CNN網絡後,從表面上看,對于每個文字圖檔來說,資料次元從32*132變成了32*384,表面上看這個資料量增多了,但資訊量并沒有增加。就像我在這長篇累牍地介紹OCR,文字是增多了,資訊量還是OCR的原理,或許能提升點可讀性或趣味性。CNN網絡是怎麼做到廢話連篇(隻增加資料量不增加資訊量)的呢?這裡隐含着一個機器學習模型中的一個頂級套路,學名叫“參數共享”。一個簡單的例子,如果有一天你的朋友很高興地告訴你他有一個新發現,“買1個蘋果要給5塊錢,買2個蘋果要給10塊錢,買3個蘋果要給15塊錢...”,相信你一定會懷疑他的智商,直接說“買n個蘋果要5*n塊錢”不就好了麼?廢話的本質在于,不做抽象總結,直接瘋狂的舉例子,給一大堆備援資料。不廢話的本質就是總結出規律和經驗,所謂的機器學習就是如這個買蘋果的例子,你期望簡單粗暴的給機器舉出大量的例子,機器便能總結出其中的規律和經驗。這個規律和經驗對應到上述的OCR例子中,便是整個模型的網絡結構和模型參數。在模型網絡上,目前主流還是靠人類智能,如對圖檔場景就上CNN網絡,對序列場景就上RNN網絡等等。網絡結構選不對的話,學習出來的模型的效果會不好。

如上面的分析中,其實在結構上,我用32個4224*384的A矩陣是完全能滿足上述的CNN在資料的輸入和輸出的次元尺寸上的要求的,但這樣的話訓練出來的模型效果會不好。因為從理論上,用32個4224*384的A矩陣的參數量是32*4224*384=51904512。這便意味着在學習過程中,模型太自由了,很容易學壞。在上面買蘋果的例子中,用越少的字就能陳述清楚這個事實的人的總結能力就越強,因為越多的文字除了引入備援外,還有可能會引入一些毫不相關的資訊對以後在使用這個規律的時候進行幹擾,假設這個蘋果的價格是用10個字就能說清楚,你用了20個字,那很有可能你其他的10個字是在描述比如下雨啊、時間點啊之類的無關資訊。這就是大名鼎鼎的“奧坎姆剃刀法則”,不要把簡單的東西複雜化!在機器學習領域主要應用于模型結構的設計和選擇中,“參數共享”的是其常用的套路之一,簡單說就是,如果32個4224*384的A矩陣參數量太大了,導緻模型在學習中太自由了,那我們就加限制讓模型不那麼自由,一定要逼它在10個字内把買蘋果的事情說清楚。方法很簡單,比如說如果這32個A長得完全一模一樣,那這裡的參數個數就隻有4224*384個而已,一下子就減少32倍,如果覺得減少32倍太狠了,那我稍微放松一點,不要求這32個A一模一樣,隻要求他們長得很像就好。

在此我稱這個剃刀大法為“不逼模型一把就不知道模型有多優秀大法”。可能有人會提出異議,雖然我允許你用20個字來說清楚蘋果的價格,并沒有抹殺你主動性很強,追求極緻,用10個字就說清楚了的可能性。如果上文中的隻用一個A矩陣就能Cover住的話,那麼我不管我給32個A還是64個A,模型都應該學出的是一模一樣的A才對。這種說法在理論上是對的,但對于目前來說卻是不現實的。

讨論這個問題還得回到機器學習的本質上,所有模型都可以抽象表示為 Y=AX,其中X是模型輸入,Y是模型輸出,A是模型,注意在此段中的A不同于上文中的A,其既包含了模型的結構和又包含了參數。模型的訓練過程便是已知X和Y,求解A。上面的問題其實就是解出來的A是不是唯一的?首先我退一步,假設我們認為在現實世界中這個問題是存在規律的,也就是說這個A在現實世界中是存在且唯一的,就像實體定律一樣,那我們的模型是否能在大量的訓練資料中捕獲到這個規律呢?

以實體上的質能方程 E=M*C^2為例,在這個模型中,模型的結構是E=M*C^2,模型的參數是光速C。這個模型愛因斯坦提出的,可以說是人類智能的結晶。如果用現在AI大法來解決這個問題呢,分兩種情況,一種是強AI,一種是弱AI,首先說最極端的弱AI的方法,也就是目前的主流的AI方法,大部分人工小部分機器智能,具體說就是人類根據自己的智慧發現E和M之間的關系滿足E=M*C^2這樣的模式,然後喂很多的E和M資料進去給機器,讓機器把這個模型中的參數C學習出來,在這個例子中C的解是唯一的,而且隻要喂給機器少量的M和C,就能把C解出來了。顯然智能部分的工作量主要在于愛因斯坦大神是如何去排除如時間、溫度、濕度等等各種亂七八糟的因素,确定E就隻和M有關,且滿足E=M*C^2。這部分工作在目前機器學習領域被叫模型的“特征選擇”,是以很多機器學習的工程師會戲稱自己為“特征工程師”。

與之相反,強AI的預期就應該是我們喂給機器一大堆的資料,如能量、品質、溫度、體積、時間、速度等等,由機器來告訴我這裡面的能量就隻和品質相關,他們的關系是E=M*C^2,并且這個常數C的值就是3.0*10^8(m/s)。在這裡,機器不但要把模型的結構學出來,還要把模型的參數學出來。要達到這個效果,首先要完成的第一步是,找到一種泛化的模型,經過加工後能描述世界上存在的所有模型結構,就像橡皮泥能被捏成各種各樣的形狀一樣。這個橡皮泥在AI領域就是神經網絡了,是以很多偏理論的AI書或者課程都喜歡在一開始給你科普下神經網絡的描述能力,證明它就是AI領域的那塊橡皮泥。既然橡皮泥有了,接下來就是怎麼捏了,難點就在這裡了,并不是生活中每個問題每個場景都能用一個個數學模型來完美表示的,就算這層成立,在這個模型結構被發現之前,沒人知道這個模型是什麼樣子,那你讓機器怎麼幫你捏出這個你本身都不知道是什麼形狀的東西?唯一的辦法就是,給機器喂很多的例子,說捏出來的東西要滿足能走路、會飛等等。其實這個問題是沒有唯一解的,機器可以給你捏出一隻小鳥、也可以給你捏出一隻小強。原因有二,其一在于你無法把所有可能的例子都喂給機器,總會有“黑天鵝”事件;其二在于喂的例子太多的話,對機器的算力要求也高,這也是為啥神經網絡很早就提出來了,這幾年才火起來的原因。

經過上面一段的探讨,希望你在此時能對機器學習的模型結構和模型參數能有一個比較直覺的了解。知道如果靠人類智能設計出模型結構,再靠機器學習出參數的話,在模型結構準确的前提下,如上面的E=M*C^2,我們隻需要喂給機器很少的資料就好,甚至模型都能有很好的解析解!但畢竟愛因斯坦隻有一個,是以更多的是我們這種平凡的人把大量的例子喂給機器,期望他能捏出我們自己都不知道的那個形狀,更别提有解析解這麼漂亮的性質了。對機器學習訓練過程熟悉的同學應該知道,機器學習捏橡皮泥用的“随機梯度下降法”,通俗點說,就是先捏一小下,看捏出來的東西是否能滿足你提的要求(即喂的訓練資料),如果不滿足再捏一小下,如此循環直至滿足你的要求才停下來。由此可見,機器捏橡皮泥的動力在于捏出來的東西不滿足你的要求。這就證明了機器是個很“懶”的東西,當他用20個字描述出蘋果的價格規律後,就沒動力去做用10個字來描述蘋果價格的規律了。是以,當你自己都不知道你想讓機器捏出什麼東西時,最好就是不要給機器太大的自由,這樣機器會給你捏出一個很複雜的東西,盡管能滿足你的要求,也不會很好用,因為違反了剃刀法則。而在機器學習的模型中,參數的數量越多,往往意味着更大的自由度和更複雜的結構,出現“過拟合”現象。是以很多經典的網絡結果中都會使用一些技巧來做“參數共享”,達到減少參數的目的,如CNN網絡中使用的卷積的方式來做參數共享,LSTM中引入了一個變化不那麼劇烈的産量C矩陣來實作參數共享。

2. 牛刀小試:LSTM等你扒

經過上面小節的探讨,相信你已經get到分析機器學習的一些套路了,最後以雙向LSTM來練下手吧。

OCR性能優化:從神經網絡到橡皮泥

如上圖,首先看LSTM網絡的輸入和輸出,最明顯能看到的輸入有32個27*384的紫色矩陣,輸出是32個27*256的矩陣,其中27*256是由兩個27*128拼湊而成,分别由前向LSTM和反向LSTM網絡輸出。為了簡單,我們暫時隻看前向LSTM,這樣的話其實輸入就是32個27*384的矩陣,輸出是32個27*128 的矩陣。根據上文中分析的“降維器”套路,這裡需要32個384*128的矩陣。在根據“參數共享”套路,真正的單個LSTM單元的結構如下圖所示:

OCR性能優化:從神經網絡到橡皮泥

由圖可知,真正的LSTM單元中并不是一個簡單的384*128的矩陣A,而是把LSTM單元序列中的上一個單元的輸出節點H拉下來和輸入X拼在一起,形成一個27*512的輸入,在乘以一個512*512的參數矩陣,再聯合上一個序列輸出的控制節點C對得到的資料進行加工,把512維降到128維,最後得到兩個輸出,一個是27*128的新輸出節點H,一個是27*128的新控制節點C。這個新輸出的H和C會被引入到下一個LSTM單元,對下一個LSTM單元的輸出進行影響。

在這裡,可以看到由于矩陣C和矩陣H的存在,即使LSTM序列32個單元中的那個512*512的參數矩陣是一模一樣的,即便每個單元的輸入H和X之間的關系都是不大一樣的,但由于都是乘以一樣的512*512矩陣得到的,是以盡管不一樣,互相間應該還是比較像,因為他們遵循了一套規律(那個一模一樣的512*512矩陣)。在這裡我們可以看到LSTM是通過把上一個單元的輸出H和輸入X拼起來作為輸入,同時引入控制矩陣C來實作剃刀大法,達到參數共享,簡化模型的目的。這種網絡結構的構造也使得目前序列單元的輸出和上個序列單元的輸出産生聯系,适用于序列場景的模組化,如OCR、NLP、機器翻譯和語音識别等等。

在這裡我們還能看到,雖然神經網絡是那塊橡皮泥,但由于喂不了所有的情況的資料、機器算力不支援、或者我們想提高機器的學習速度,在目前的AI應用場景中,我們都是給根據實際應用場景精和自己的先驗知識對網絡結構進行精心地設計,再把這塊由人類捏得差不多的橡皮泥交由機器來捏。是以我更喜歡稱現在是個弱AI的時代,在這個算力還可以的時代,我們的研究人員一方面緻力于不斷地去研究各中不同的場景中的的通用網絡,如用于圖像的CNN、用于序列RNN、LSTM、GRU等等,一方面緻力于優化神經網絡的學習方式,如基于SDG的各種優化變種算法和強化學習的訓練方式等等,這些都是在試圖化減少AI需要的算力資源。

相信在人類的努力下,強AI的時代會到來。

點選關注,第一時間了解華為雲新鮮技術~

繼續閱讀