作者:Harald Scheidl
編譯:ronghuaiyang
非常直觀的解釋了文字識別中非常常用的CTC損失和解碼的操作。
如果你想讓計算機識別文本,神經網絡(NN)是一個不錯的選擇,因為它們目前的表現優於所有其他方法。這裡的神經網絡通常由卷積層(CNN)和遞歸層(RNN)組成,前者用於提取特徵序列,後者用於通過該序列傳遞信息。它輸出每個序列元素的字符得分,它只需要用一個矩陣來表示。現在,我們想對這個矩陣做兩件事:
這兩項任務都由CTC操作完成。手寫識別系統概述如圖1所示。
讓我們更仔細地看看CTC操作,並討論它是如何工作的,剖析一下它所基於的複雜公式背後的巧妙思想。最後,如果你感興趣,我會給你一些參考資料,你可以在其中找到Python代碼和(不太複雜的)公式。
圖1:手寫字識別的概要圖
我們為什麼要用CTC
當然,我們可以用文本行圖像創建一個數據集,然後為圖像的每個水平位置指定相應的字符,如圖2所示。然後,我們可以訓練一個神經網絡輸出每個水平位置的字符得分。然而,這種解決方案有兩個問題:
圖2:圖像中每個水平位置的標註
CTC如何工作
正如已經討論過的,我們不希望在每個水平位置上對圖像進行標註(從現在開始,我們將其稱為time-step)。神經網絡的訓練將以CTC損失函數為指導。我們只將神經網絡的輸出矩陣和相應的ground-truth(GT)文本輸入到CTC損失函數中。但是它如何知道每個字符出現在哪裡呢?它不知道。相反,它嘗試圖像中GT文本的所有可能的對齊,並對所有的得分求和。這樣,如果對齊分數的求和值很高,則GT文本的分數就很高。
文本編碼
還有一個問題是如何編碼重複的字符(還記得我們說過的「too」嗎?),它通過引入一個偽字符(稱為blank,但不要將它與「真正的」blank混淆,即空白字符)來解決。在下面的文本中,這個特殊字符將被表示為「-」。我們使用一個聰明的編碼模式來解決重複字符的問題:在編碼文本時,我們可以在任何位置插入任意多的空格,而在解碼時這些空格將被刪除。但是,我們必須在重複的字符之間插入空格,比如「hello」。此外,我們可以重複每個字符,只要我們喜歡。
我們來看一些例子:
正如你所看到的,這個模式還允許我們輕鬆地創建相同文本的不同對齊,例如「t-o」和「too」以及「-to」都表示相同的文本(「to」),但是對圖像的對齊不同。該神經網絡被訓練成輸出編碼文本(編碼在神經網絡輸出矩陣中)。
損失的計算
我們需要計算給定對圖像和GT文本的損失值來訓練神經網絡。你已經知道,NN在每個時間步長輸出一個矩陣,其中包含每個字符的得分。一個極小矩陣如圖3所示:有兩個時間步長(t0, t1)和三個字符(「A」,「b」和空白「-」)。每個時間步的字符得分總和為1。
圖3:神經網絡的輸出矩陣。字符機率用顏色編碼,數值在每個矩陣條目旁邊列印。細線是表示文本「a」的路徑
此外,你已經知道損失的計算方法是將GT文本的所有可能對齊的所有得分相加,這樣,文本在圖像中出現的位置就不重要了。
一個對齊(或path,通常在文獻中稱為path)的得分是通過將相應的字符得分相乘來計算的。在上面的例子中,路徑「aa」的得分為0.4·0.4=0.16,路徑「a-」的得分為0.4·0.6=0.24,路徑「a」的得分為0.6·0.4=0.24。為了得到給定GT文本的分數,我們對與此文本對應的所有路徑的分數求和。假設示例中的GT文本是「a」:我們必須計算長度為2的所有可能路徑(因為矩陣有2個時間步長),即:「aa」、「a-」和「a-」。我們已經計算了這些路徑的得分,所以我們只需要對它們求和,得到0.4·0.4+0.4·0.6+0.6·0.4=0.64。假設GT文本為「」,我們看到只有一條對應的路徑,即「--」,得到總分0.6·0.6=0.36。
如果你仔細看,你會發現我們計算的是GT文本的機率,而不是損失。然而,損失只是機率的負對數。損失值通過神經網絡反向傳播,神經網絡的參數根據所使用的優化器進行更新,在此不再贅述。
解碼
當我們有一個訓練過的神經網絡時,我們通常想要用它來識別以前沒有見過的圖像中的文本。或者用更專業的術語來說>我們希望計算給定神經網絡輸出矩陣的最有可能的文本。你已經知道了計算給定文本得分的方法。但這一次,我們沒有得到任何文本,事實上,這正是我們要找的文本。如果只有幾個時間步驟和字符,那麼嘗試所有可能的文本都是可行的,但是對於實際的情況下,這是不可行的。
一個簡單而快速的算法是最佳路徑解碼,它包括兩個步驟:
如圖4所示。字符是「a」、「b」和「-」(空白)。有5個時間步驟。讓我們對這個矩陣應用我們最好的路徑解碼器:t0最可能的字符是「a」,同樣適用於t1和t2。空白字符在t3處得分最高。最後,「b」最有可能出現在t4。這給出了路徑aaa-b。我們刪除重複的字符,這將生成「a-b」,然後從剩餘的路徑中刪除任何空白,這將生成文本「ab」,我們將其輸出為可識別的文本。
圖4:神經網絡的輸出矩陣,粗虛線表示最佳路徑。
當然,最佳路徑解碼只是一種近似。對於它給出錯誤結果的例子很容易構造:如果你從圖3中解碼矩陣,你將得到「」作為可識別的文本。但是我們已經知道""的機率只有0.36而"a"的機率是0.64。然而,這種近似算法在實際應用中往往能得到較好的結果。還有一些更高級的解碼器,如beam-search解碼器、prefix-search解碼器和令牌傳遞解碼器,它們也利用語言結構的信息來改進解碼結果。
總結
首先,我們研究了神經網絡解決方案所產生的問題。然後,我們看到CTC是如何解決這些問題的。然後,我們通過研究CTC如何編碼文本、如何進行損失計算以及如何解碼CTC訓練的神經網絡的輸出來研究CTC的工作原理。
這將使你可以很好地理解在TensorFlow中調用ctc_loss或ctc_greedy_decoder等函數時,幕後發生了什麼。然而,當你想要自己實現CTC時,你需要了解更多的細節,尤其是想使它運行得更快。Graves等人[1]介紹了CTC運算,並給出了所有相關的數學計算。如果你對如何改進解碼感興趣,請參閱有關beam-search解碼的文章。我用Python和c++實現了一些解碼器和損失函數,你可以在github上找到。最後,如果你想了解如何識別(手寫)文本的全局,請參閱我關於如何構建手寫文本識別系統的文章。
英文原文:https://towardsdatascience.com/intuitively-understanding-connectionist-temporal-classification-3797e43a86c
請長按或掃描二維碼關注本公眾號