最近因為相關項目需要考慮中文文本檢錯,然后就發現了愛奇藝發布的號稱SOTA的FASPell已經開源代碼,所以開始着手實現。
檢錯思想兩步:一,掩碼語言模型(MLM)產生候選字符;二,CSD過濾候選字符。
資源與數據文件
開源代碼中不包含任何處理好的數據,全部需要自己處理。訓練和測試使用的SIGHAN數據沒有問題。但是所需的char_meta.txt文件構建較為困難,其由字音和字形兩部分特征構成。字音在unihan database可以檢索到,但字形特征依照論文闡述是使用漢字的完整帶結構筆畫級分解,但其提供的kanji database中的結構信息有限,對於簡單結構的漢字未做分解,也沒有結構信息。雖然github中作者回應可以分解漢字為文件中出現過的字,遞歸直到無法分解,然后使用cjklib庫對遞歸無法分解的漢字獲取其筆畫順序。但這樣雖然可以拆分筆畫,但是缺少了筆畫間的結構。我按照該方法制作了一個帶部分結構的筆畫級分解文件。
U+4EAC 京 jing1;ging1;KYENG;KYOU,KEI,KIN;kinh ⿳⿱㇔㇐㇑㇕㇐㇚㇒㇔
U+4EAD 亭 ting2;ting4;CENG;TEI,CHOU,CHIN;đình ⿱⿳⿱㇔㇐㇑㇕㇐㇔㇖⿱㇐㇚
U+4EAE 亮 liang4,liang2;loeng6;LYANG;RYOU;null ⿱⿳⿱㇔㇐㇑㇕㇐㇔㇖㇓㇈
模型訓練
模型訓練步驟有三個:預訓練掩碼語言模型,微調訓練掩碼語言模型和訓練CSD過濾器。在原作者github中講述較為清楚,因此只簡單敘述一下,不再復述細節。
預訓練掩碼語言模型選擇直接使用預訓練好的中文BERT模型。然而,預訓練模型進行隨機mask的位置和實際的拼寫錯誤位置有較大差異,因此需要使用拼寫檢錯的訓練集進行微調。微調完成之后的掩碼語言模型就可以針對輸入句子的每個位置計算出其置信度較高的topn候選集合判斷是否存在拼寫錯誤,再將這些候選送到CSD過濾器中過濾並確定修改的候選字。而對於候選集合的過濾方法,則是將其按照字音相似和字形相似分別評估相似度,將置信度和相似度結合進行過濾,因此,訓練CSD過濾器的過程較為繁瑣,耗時較長,且需要手動確定過濾線(對結果影響較大)。
以上三個訓練步驟完成之后,CSD過濾器訓練會產生置信度-相似度散點圖,根據散點圖的分布來確定過濾曲線,然后使用一些切線來近似曲線。論文中闡述檢測正確且糾正正確的樣本通常分布在散點圖的右上方,因此可以使用曲線對其進行過濾。訓練CSD時我使用了大量的SIGHAN數據,產生的散點圖並不如論文中那么完美,為了保證低誤判,我僅僅考慮了檢測和糾正都正確的case來划分過濾曲線。
實踐的一些問題
除了之前的char_meta.txt的問題之外,測試時還發現了對齊錯誤問題。
經過排檢,發現對齊問題的原因來自於句子中的數字。分詞后,有些數字會被打包在一起作為一個token送到BERT中,因此產生了對齊偏差。雖然代碼中考慮到了該問題,但僅僅針對兩位數字的情況進行了處理,一旦3個以上數字被分為了一個token,句子必定出現對齊錯誤問題。因此extension()方法需要修改。
此外,由於訓練數據都是繁體字,進行微調之后模型對繁體字的偏好程度增加,這樣訓練出來的模型在測試時會出現把某個字更改為其繁體字形式的錯誤。之后我首先用zhconv將訓練數據轉為簡體字,再進行訓練測試結果沒問題。但由於有些特殊的字的用法原因,如“着”和“著”,使得句子“...看着...”被改為了“...看著...”。對於這些特例,可以使用特殊過濾器進行過濾。
我認為FASPell主要面向的還是字形相似(OCR)的錯誤,也的確優先檢測這類錯誤。如果檢測對象錯誤分布偏向於字音(語音識別、拼音輸入)的話,可以僅僅開啟字音相似檢測,或者調整代碼中的字音字形檢測順序和修改字音過濾線進行靈活適應。
相關鏈接
該項目的論文及github如下。
