在以前的OCR任務(wù)中,識別過程分為兩步:單字切割和分類任務(wù)。我們一般都會講一連串文字的文本文件先利用投影法切割出單個字體,在送入CNN里進(jìn)行文字分類。但是此法已經(jīng)有點過時了,現(xiàn)在更流行的是基于深度學(xué)習(xí)的端到端的文字識別,即我們不需要顯式加入文字切割這個環(huán)節(jié),而是將文字識別轉(zhuǎn)化為序列學(xué)習(xí)問題,雖然輸入的圖像尺度不同,文本長度不同,但是經(jīng)過DCNN和RNN后,在輸出階段經(jīng)過一定的翻譯后,就可以對整個文本圖像進(jìn)行識別,也就是說,文字的切割也被融入到深度學(xué)習(xí)中去了。 現(xiàn)今基于深度學(xué)習(xí)的端到端OCR技術(shù)有兩大主流技術(shù):CRNN OCR和attention OCR。其實這兩大方法主要區(qū)別在于最后的輸出層(翻譯層),即怎么將網(wǎng)絡(luò)學(xué)習(xí)到的序列特征信息轉(zhuǎn)化為最終的識別結(jié)果。這兩大主流技術(shù)在其特征學(xué)習(xí)階段都采用了CNN+RNN的網(wǎng)絡(luò)結(jié)構(gòu),CRNN OCR在對齊時采取的方式是CTC算法,而attention OCR采取的方式則是attention機(jī)制。本文將介紹應(yīng)用更為廣泛的CRNN算法。 網(wǎng)絡(luò)結(jié)構(gòu)包含三部分,從下到上依次為:
端到端OCR的難點在哪兒呢?在于怎么處理不定長序列對齊問題!CRNN OCR其實是借用了語音識別中解決不定長語音序列的思路。與語音識別問題類似,OCR可建模為時序依賴的詞匯或者短語識別問題。基于聯(lián)結(jié)時序分類(Connectionist Temporal Classification, CTC)訓(xùn)練RNN的算法,在語音識別領(lǐng)域顯著超過傳統(tǒng)語音識別算法。一些學(xué)者嘗試把CTC損失函數(shù)借鑒到OCR識別中,CRNN 就是其中代表性算法。CRNN算法輸入100*32歸一化高度的詞條圖像,基于7層CNN(普遍使用VGG16)提取特征圖,把特征圖按列切分(Map-to-Sequence),每一列的512維特征,輸入到兩層各256單元的雙向LSTM進(jìn)行分類。在訓(xùn)練過程中,通過CTC損失函數(shù)的指導(dǎo),實現(xiàn)字符位置與類標(biāo)的近似軟對齊。 CRNN借鑒了語音識別中的LSTM+CTC的建模方法,不同點是輸入進(jìn)LSTM的特征,從語音領(lǐng)域的聲學(xué)特征(MFCC等),替換為CNN網(wǎng)絡(luò)提取的圖像特征向量。CRNN算法最大的貢獻(xiàn),是把CNN做圖像特征工程的潛力與LSTM做序列化識別的潛力,進(jìn)行結(jié)合。它既提取了魯棒特征,又通過序列識別避免了傳統(tǒng)算法中難度極高的單字符切分與單字符識別,同時序列化識別也嵌入時序依賴(隱含利用語料)。在訓(xùn)練階段,CRNN將訓(xùn)練圖像統(tǒng)一縮放100×32(w × h);在測試階段,針對字符拉伸導(dǎo)致識別率降低的問題,CRNN保持輸入圖像尺寸比例,但是圖像高度還是必須統(tǒng)一為32個像素,卷積特征圖的尺寸動態(tài)決定LSTM時序長度。這里舉個例子 現(xiàn)在輸入有個圖像,為了將特征輸入到Recurrent Layers,做如下處理:
CRNN中需要解決的問題是圖像文本長度是不定長的,所以會存在一個對齊解碼的問題,所以RNN需要一個額外的搭檔來解決這個問題,這個搭檔就是著名的CTC解碼。 那么CTC有什么好處?因手寫字符的隨機(jī)性,人工可以標(biāo)注字符出現(xiàn)的像素范圍,但是太過麻煩,ctc可以告訴我們哪些像素范圍對應(yīng)的字符: 我們知道,CRNN中RNN層輸出的一個不定長的序列,比如原始圖像寬度為W,可能其經(jīng)過CNN和RNN后輸出的序列個數(shù)為S,此時我們要將該序列翻譯成最終的識別結(jié)果。RNN進(jìn)行時序分類時,不可避免地會出現(xiàn)很多冗余信息,比如一個字母被連續(xù)識別兩次,這就需要一套去冗余機(jī)制,但是簡單地看到兩個連續(xù)字母就去冗余的方法也有問題,比如cook,geek一類的詞,所以CTC有一個blank機(jī)制來解決這個問題。這里舉個例子來說明。 如上圖所示,我們要識別這個手寫體圖像,標(biāo)簽為“ab”,經(jīng)過CNN+RNN學(xué)習(xí)后輸出序列向量長度為5,即t0~t4,此時我們要將該序列翻譯為最后的識別結(jié)果。我們在翻譯時遇到的第一個難題就是,5個序列怎么轉(zhuǎn)化為對應(yīng)的兩個字母?重復(fù)的序列怎么解決?剛好位于字與字之間的空白的序列怎么映射?這些都是CTC需要解決的問題。 我們從肉眼可以看到,t0,t1,t2時刻都應(yīng)映射為“a”,t3,t4時刻都應(yīng)映射為“b”。如果我們將連續(xù)重復(fù)的字符合并成一個輸出的話,即“aaabb”將被合并成“ab”輸出。但是這樣子的合并機(jī)制是有問題的,比如我們的標(biāo)簽圖像時“aab”時,我們的序列輸出將可能會是“aaaaaaabb”,這樣子我們就沒辦法確定該文本應(yīng)被識別為“aab”還是“ab”。CTC為了解決這種二義性,提出了插入blank機(jī)制,比如我們以“-”符號代表blank,則若標(biāo)簽為“aaa-aaaabb”則將被映射為“aab”,而“aaaaaaabb”將被映射為“ab”。引入blank機(jī)制,我們就可以很好地處理了重復(fù)字符的問題了。 但我們還注意到,“aaa-aaaabb”可以映射為“aab”,同樣地,“aa-aaaaabb”也可以映射為“aab”,也就是說,存在多個不同的字符組合可以映射為“aab”,更總結(jié)地說,一個標(biāo)簽存在一條或多條的路徑。比如下面“state”這個例子,也存在多條不同路徑映射為"state": 上面提到,RNN層輸出的是序列中概率矩陣,那么 其中,表示第一個序列輸出“-”的概率,那么對于輸出某條路徑的概率為各個序列概率的乘積。所以要得到一個標(biāo)簽可以有多個路徑來獲得,從直觀上理解就是,我們輸出一張文本圖像到網(wǎng)絡(luò)中,我們需要使得輸出為標(biāo)簽L的概率最大化,由于路徑之間是互斥的,對于標(biāo)注序列,其條件概率為所有映射到它的路徑概率之和: 其中的意思是,所有可以合并成l的所有路徑集合。 這種通過映射B和所有候選路徑概率之和的方式使得CTC不需要對原始的輸入序列進(jìn)行準(zhǔn)確的切分,這使得RNN層輸出的序列長度>label長度的任務(wù)翻譯變得可能。CTC可以與任意的RNN模型,但是考慮到標(biāo)注概率與整個輸入串有關(guān),而不是僅與前面小窗口范圍的片段相關(guān),因此雙向的RNN/LSTM模型更為適合。 ctc會計算loss ,從而找到最可能的像素區(qū)域?qū)?yīng)的字符。事實上,這里loss的計算本質(zhì)是對概率的歸納: 如上圖,對于最簡單的時序為2的(t0t1)的字符識別,可能的字符為“a”,“b”和“-”,顏色越深代表概率越高。我們?nèi)绻扇∽畲蟾怕事窂浇獯a的方法,一看就是“--”的概率最大,真實字符為空即“”的概率為0.6*0.6=0.36。 但是我們忽略了一點,真實字符為“a”的概率不只是”aa” 即0.4*0.4 , 事實上,“aa”, “a-“和“-a”都是代表“a”,所以,輸出“a”的概率為:
所以“a”的概率比空“”的概率高!可以看出,這個例子里最大概率路徑和最大概率序列完全不同,所以CTC解碼通常不適合采用最大概率路徑的方法,而應(yīng)該采用前綴搜索算法解碼或者約束解碼算法。 通過對概率的計算,就可以對之前的神經(jīng)網(wǎng)絡(luò)進(jìn)行反向傳播更新。類似普通的分類,CTC的損失函數(shù)O定義為負(fù)的最大似然,為了計算方便,對似然取對數(shù)。
我們的訓(xùn)練目標(biāo)就是使得損失函數(shù)O優(yōu)化得最小即可。 |
|