轉載自:https://zhuanlan.zhihu.com/p/43534801
文字識別也是圖像領域一個常見問題。然而,對於自然場景圖像,首先要定位圖像中的文字位置,然後才能進行識別。
所以一般來說,從自然場景圖片中進行文字識別,需要包括2個步驟:
- 文字檢測:解決的問題是哪裏有文字,文字的範圍有多少
- 文字識別:對定位好的文字區域進行識別,主要解決的問題是每個文字是什麼,將圖像中的文字區域進轉化爲字符信息。
對於文字檢測不瞭解的讀者,請參考本專欄文章:
場景文字檢測—CTPN原理與實現本文的重點是如何對已經定位好的文字區域圖片進行識別。
最簡單的文字識別基於單字符定位+分類,即定位單個文字區域後直接進行分類。
基於RNN文字識別算法主要有兩個框架:
- CNN+RNN+CTC(CRNN+CTC)
- CNN+Seq2Seq+Attention
本文主要介紹第一種框架CRNN+CTC,對應代碼(tf1.15實現)如下,本文介紹的CRNN網絡結構都基於此代碼。另外該代碼已經支持不定長英文識別。
bai-shang/crnn_ctc_ocr_tfCRNN基本網絡結構
整個CRNN網絡可以分爲三個部分:
假設輸入圖像大小爲 ,注意提及圖像都是 形式。
- Convlutional Layers
這裏的卷積層就是一個普通的CNN網絡,用於提取輸入圖像的Convolutional feature maps,即將大小爲 的圖像轉換爲 大小的卷積特徵矩陣,網絡細節請參考本文給出的實現代碼。
- Recurrent Layers
這裏的循環網絡層是一個深層雙向LSTM網絡,在卷積特徵的基礎上繼續提取文字序列特徵。對RNN不瞭解的讀者,建議參考:
完全解析RNN, Seq2Seq, Attention注意力機制所謂深層RNN網絡,是指超過兩層的RNN網絡。對於單層雙向RNN網絡,結構如下:
而對於深層雙向RNN網絡,主要有2種不同的實現:
tf.nn.bidirectional_dynamic_rnn
tf.contrib.rnn.stack_bidirectional_dynamic_rnn
在CRNN中顯然使用了第二種stack形深層雙向結構。
由於CNN輸出的Feature map是大小,所以對於RNN最大時間長度 (即有25個時間輸入,每個輸入 列向量有 )。
- Transcription Layers
將RNN輸出做softmax後,爲字符輸出。
關於代碼中輸入圖片大小的解釋:
在本文給出的實現中,爲了將特徵輸入到Recurrent Layers,做如下處理:
- 首先會將圖像在固定長寬比的情況下縮放到 大小( 代表任意寬度)
- 然後經過CNN後變爲
- 針對LSTM設置 ,即可將特徵輸入LSTM。
所以在處理輸入圖像的時候,建議在保持長寬比的情況下將高縮放到 ,這樣能夠儘量不破壞圖像中的文本細節(當然也可以將輸入圖像縮放到固定寬度,但是這樣由於破壞文本的形狀,肯定會造成性能下降)。
考慮訓練Recurrent Layers時的一個問題:
對於Recurrent Layers,如果使用常見的Softmax cross-entropy loss,則每一列輸出都需要對應一個字符元素。那麼訓練時候每張樣本圖片都需要標記出每個字符在圖片中的位置,再通過CNN感受野對齊到Feature map的每一列獲取該列輸出對應的Label才能進行訓練,如圖9。
在實際情況中,標記這種對齊樣本非常困難(除了標記字符,還要標記每個字符的位置),工作量非常大。另外,由於每張樣本的字符數量不同,字體樣式不同,字體大小不同,導致每列輸出並不一定能與每個字符一一對應。
當然這種問題同樣存在於語音識別領域。例如有人說話快,有人說話慢,那麼如何進行語音幀對齊,是一直以來困擾語音識別的巨大難題。
所以CTC提出一種對不需要對齊的Loss計算方法,用於訓練網絡,被廣泛應用於文本行識別和語音識別中。
Connectionist Temporal Classification(CTC)詳解
在分析過程中儘量保持和原文符號一致。
Connectionist Temporal Classification: Labelling Unsegmented Sequence Data with Recurrent Neural Networks整個CRNN的流程如圖10。先通過CNN提取文本圖片的Feature map,然後將每一個channel作爲 的時間序列輸入到LSTM中。
爲了說明問題,我們定義:
- CNN Feature map
Feature map的每一列作爲一個時間片輸入到LSTM中。設Feature map大小爲 (圖11中 , )。下文中的時間序列 都從 開始,即 。
定義爲:
其中 每一列 爲:
- LSTM
LSTM的每一個時間片後接softmax,輸出 是一個後驗概率矩陣,定義爲:
其中, 的每一列 爲:
其中 代表需要識別的字符集合長度。由於 是概率,所以服從概率假設:
對 每一列進行 操作,即可獲得每一列輸出字符的類別。
那麼LSTM可以表示爲:
其中 代表LSTM的參數。LSTM在輸入和輸出間做了如下變換:
- 空白blank符號
如果要進行 的26個英文字符識別,考慮到有的位置沒有字符,定義插入blank的字符集合:
其中blank表示當前列對應的圖像位置沒有字符(下文以符號表示blank)。
- 關於 變換
定義變換 如下(原文是大寫的 ,知乎沒這個符號):
其中 是上述加入blank的長度爲 的字符集合,經過 變換後得到原始 ,顯然對於的最大長度有 。
舉例說明,當 時:
對於字符間有blank符號的則不合並:
當獲得LSTM輸出後進行變換,即可獲得輸出結果。顯然 變換不是單對單映射,例如對於不同的都可獲得英文單詞state。同時 成立。
那麼CTC怎麼做?
對於LSTM給定輸入 的情況下,輸出爲 的概率爲:
其中 代表所有經過 變換後是 的路徑 。
其中,對於任意一條路徑 有:
注意這裏的 中的 ,下標 表示 路徑的每一個時刻;而上面 的下標表示不同的路徑。兩個下標含義不同注意區分。
*注意上式 成立有條件,此項不做進一步討論,有興趣的讀者請自行研究。
如對於 的路徑 來說:
實際情況中一般手工設置 ,所以有非常多條 路徑,即 非常大,無法逐條求和直接計算 。所以需要一種快速計算方法。
CTC的訓練目標
CTC的訓練過程,本質上是通過梯度 調整LSTM的參數 ,使得對於輸入樣本爲 時使得 取得最大。
例如下面圖14的訓練樣本,目標都是使得 時的輸出 變大。
CTC借用了HMM的“向前—向後”(forward-backward)算法來計算
要計算 ,由於有blank的存在,定義路徑 爲在路徑 每兩個元素以及頭尾插入blank。那麼對於任意的 都有 (其中 )。如:
顯然 ,其中 是路徑的最大長度,如上述例子中 。
定義所有經 變換後結果是 且在 時刻結果爲 (記爲 )的路徑集合爲 。
求導:
注意上式中第二項與 無關,所以:
而上述 就是恰好與概率 相關的路徑,即 時刻都經過 ( )。
舉例說明,還是看上面的例子 (這裏的下標 代表不同的路徑):
藍色路徑 :
紅色路徑 :
還有 沒有畫出來。
而 在 時恰好都經過 (此處下標代表路徑 的 時刻的字符)。所有類似於 經過 變換後結果是 且在 的路徑集合表示爲 。
觀察 。記 藍色爲 , 紅色路徑爲 , 可以表示:
那麼 可以表示爲:
計算:
爲了觀察規律,單獨計算 。
不妨令:
那麼可以表示爲:
推廣一下,所有經過 變換爲 且 的路徑(即 )可以寫成如下形式:
進一步推廣,所有經過 變換爲 且 的路徑(即 )也都可以寫作:
所以,定義前向遞推概率和 :
對於一個長度爲 的路徑 ,其中 代表該路徑前 個字符, 代表後 個字符。
其中 表示前 個字符 經過 變換爲的 的前半段子路徑。 代表了 時刻經過 的路徑概率中 概率之和,即前向遞推概率和。
由於當 時路徑只能從blank或 開始,所以 有如下性質:
如上面的例子中 , , 。對於所有 路徑,當 時只能從blank和 字符開始。
圖16是 時經過壓縮路徑後能夠變爲 的所有路徑 。觀察圖15會發現對於 有如下遞推關係:
也就是說,如果 時刻是字符 ,那麼 時刻只可能是字符 三選一,否則經過 變換後無法壓縮成 。
那麼更一般的:
同理,定義反向遞推概率和 :
其中 表示後 個字符 經過 變換爲的 的後半段子路徑。 代表了 時刻經過 的路徑概率中 概率之和,即反向遞推概率和。
由於當 時路徑只能以blank或 結束,所以有如下性質:
如上面的例子中 , , , 。對於所有 路徑,當 時只能以 (blank字符)或 字符結束。
觀察圖15會發現對於 有如下遞推關係
與 同理,對於 有如下遞推關係:
那麼forward和backward相乘有:
或:
注意, 可以通過圖16的關係對應,如 ,。
對比 :
可以得到 與forward和backward遞推公式之間的關係:
* 爲什麼有上式 成立呢?
回到圖15,爲了方便分析,假設只有 共4條在 時刻經過字符 且 變換爲 的路徑,即 :
那麼此時(注意雖然表示路徑用 加法,但是由於 和 兩件獨立事情同時發生,所以 路徑的概率 是乘法):
則有:
訓練CTC
對於LSTM,有訓練集合 ,其中 是圖片經過CNN計算獲得的Feature map, 是圖片對應的OCR字符label(label裏面沒有blank字符)。
現在我們要做的事情就是:通過梯度調整LSTM的參數,使得對於輸入樣本爲時有 取得最大。所以如何計算梯度纔是核心。
單獨來看CTC輸入(即LSTM輸出) 矩陣中的某一個值 (注意 與 含義相同,都是在 時 的概率):
上式中的 是通過遞推計算的常數,任何時候都可以通過遞推快速獲得,那麼即可快速計算梯度 ,之後梯度上升算法你懂的。
CTC編程接口
在Tensorflow中官方實現了CTC接口:
tf.nn.ctc_loss(
labels,
inputs,
sequence_length,
preprocess_collapse_repeated=False,
ctc_merge_repeated=True,
ignore_longer_outputs_than_inputs=False,
time_major=True
)
在Pytorch中需要使用針對框架編譯的warp-ctc:https://github.com/SeanNaren/warp-ctc
2020.4更新,目前Pytorch已經有CTC接口:
torch.nn.CTCLoss(blank=0,reduction='mean',zero_infinity=False)
CTC總結
CTC是一種Loss計算方法,用CTC代替Softmax Loss,訓練樣本無需對齊。CTC特點:
- 引入blank字符,解決有些位置沒有字符的問題
- 通過遞推,快速計算梯度
看到這裏你也應該大致瞭解MFCC+CTC在語音識別中的應用了(圖17來源)。
CRNN+CTC總結
這篇文章的核心,就是將CNN/LSTM/CTC三種方法結合:
- 首先CNN提取圖像卷積特徵
- 然後LSTM進一步提取圖像卷積特徵中的序列特徵
- 最後引入CTC解決訓練時字符無法對齊的問題
即提供了一種end2end文字圖片識別算法,也算是方向的簡單入門。
特別說明
一般情況下對一張圖像中的文字進行識別需要以下步驟
- 定位文稿中的圖片,表格,文字區域,區分文字段落(版面分析)
- 進行文本行識別(識別)
- 使用NLP相關算法對文字識別結果進行矯正(後處理)
本文介紹的CRNN框架只是步驟2的一種識別算法,其他非本文內容。CTC你學會(fei)了麼?
想了解其他文字識別方法,請點這裏:
文字識別方法整理求求你們點個贊吧!
本文章只是介紹ctc原理,不包含1v1輔導服務。個人工程問題切勿提問和私聊:
- 如何做畢設
- 如何識別中文
- 領導要求識別身份證和發票
- 在xxx數據集效果
- 關於xxx代碼的xxx問題