【深度学习】PyCorrector中文文本纠错实战
PyCorrector中文文本糾錯實戰
- PyCorrector糾錯工具實踐和代碼詳解
- 模型調參demo
1. 簡介
中文文本糾錯工具。音似、形似錯字(或變體字)糾正,可用于中文拼音、筆畫輸入法的錯誤糾正。python3.6開發。
pycorrector依據語言模型檢測錯別字位置,通過拼音音似特征、筆畫五筆編輯距離特征及語言模型困惑度特征糾正錯別字。
1.1 在線Demo
https://www.borntowin.cn/product/corrector
1.2 Question
中文文本糾錯任務,常見錯誤類型包括:
- 諧音字詞,如 配副眼睛-配副眼鏡
- 混淆音字詞,如 流浪織女-牛郎織女
- 字詞順序顛倒,如 伍迪艾倫-艾倫伍迪
- 字詞補全,如 愛有天意-假如愛有天意
- 形似字錯誤,如 高梁-高粱
- 中文拼音全拼,如 xingfu-幸福
- 中文拼音縮寫,如 sz-深圳
- 語法錯誤,如 想象難以-難以想象
當然,針對不同業務場景,這些問題并不一定全部存在,比如輸入法中需要處理前四種,搜索引擎需要處理所有類型,語音識別后文本糾錯只需要處理前兩種,
其中’形似字錯誤’主要針對五筆或者筆畫手寫輸入等。
1.3 Solution
1.3.1 規則的解決思路
整合這兩種粒度的疑似錯誤結果,形成疑似錯誤位置候選集;
1.3.2 深度模型的解決思路
1.4 Feature
1.4.1 模型
- kenlm:kenlm統計語言模型工具
- rnn_attention模型:參考Stanford University的nlc模型,該模型是參加2014英文文本糾錯比賽并取得第一名的方法
- rnn_crf模型:參考阿里巴巴2016參賽中文語法糾錯比賽CGED2018并取得第一名的方法(整理中)
- seq2seq_attention模型:在seq2seq模型加上attention機制,對于長文本效果更好,模型更容易收斂,但容易過擬合
- transformer模型:全attention的結構代替了lstm用于解決sequence to sequence問題,語義特征提取效果更好
- bert模型:中文fine-tuned模型,使用MASK特征糾正錯字
- conv_seq2seq模型:基于Facebook出品的fairseq,北京語言大學團隊改進ConvS2S模型用于中文糾錯,在NLPCC-2018的中文語法糾錯比賽中,是唯一使用單模型并取得第三名的成績
1.4.2 錯誤檢測
- 字粒度:語言模型困惑度(ppl)檢測某字的似然概率值低于句子文本平均值,則判定該字是疑似錯別字的概率大。
- 詞粒度:切詞后不在詞典中的詞是疑似錯詞的概率大。
1.4.3 錯誤糾正
- 通過錯誤檢測定位所有疑似錯誤后,取所有疑似錯字的音似、形似候選詞,
- 使用候選詞替換,基于語言模型得到類似翻譯模型的候選排序結果,得到最優糾正詞。
1.4.4 思考
2. 安裝
作者開源代碼中介紹有兩種安裝方式:
- pip安裝
用戶:適合做工程實踐,不關心算法細節,直接調包使用。
- 源碼安裝
用戶:希望了解代碼實現,做一些深層次修改。
2.1 源碼安裝步驟詳解
我們詳細講解第二種-源碼安裝方式。除了完成上面源碼安裝步驟外,我們還需要安裝一些必要的庫。
2.1.1 安裝必要的庫
pip install -r requirements.txt2.1.2 安裝kenlm
kenlm是一個統計語言模型的開源工具,如圖所示,代碼96%都是C++實現的,所以效率極高,訓練速度快,在GitHub上現有1.1K Star
pip安裝kenlm
安裝命令如下
pip install kenlm- 筆者嘗試直接pip安裝,報了如下錯誤,機器環境(MAC OS 10.15.4)。
若報錯,則進行如下源碼安裝kenlm,安裝成功則跳過該步驟。
源碼安裝kenlm
下載kenlm代碼
運行安裝命令
如下圖所示,則已經安裝成功。
3. 環境測試
3.1 源碼結構
代碼結構如下(clone時間2020/5/5):
. ├── LICENSE ├── README.md ├── _config.yml ├── build │?? ├── bdist.macosx-10.7-x86_64 │?? └── lib ├── dist │?? └── pycorrector-0.2.7-py3.6.egg ├── docs │?? ├── git_image │?? ├── logo.svg │?? └── 基于深度學習的中文文本自動校對研究與實現.pdf ├── examples │?? ├── base_demo.py │?? ├── detect_demo.py │?? ├── disable_char_error.py │?? ├── en_correct_demo.py │?? ├── load_custom_language_model.py │?? ├── my_custom_confusion.txt │?? ├── traditional_simplified_chinese_demo.py │?? └── use_custom_confusion.py ├── pycorrector │?? ├── __init__.py │?? ├── __main__.py │?? ├── __pycache__ │?? ├── bert │?? ├── config.py │?? ├── conv_seq2seq │?? ├── corrector.py │?? ├── data │?? ├── deep_context │?? ├── detector.py │?? ├── en_spell.py │?? ├── seq2seq_attention │?? ├── transformer │?? ├── utils │?? └── version.py ├── pycorrector.egg-info │?? ├── PKG-INFO │?? ├── SOURCES.txt │?? ├── dependency_links.txt │?? ├── not-zip-safe │?? ├── requires.txt │?? └── top_level.txt ├── requirements-dev.txt ├── requirements.txt ├── setup.py └── tests├── bert_corrector_test.py├── char_error_test.py├── confusion_test.py├── conv_s2s_interactive_demo.py├── corrector_test.py├── detector_test.py├── en_spell_test.py├── error_correct_test.py├── eval_test.py├── file_correct_test.py├── fix_bug.py├── kenlm_test.py├── memory_test.py├── ner_error_test.py├── ngram_words.txt├── speed_test.py├── test_file.txt├── tokenizer_test.py├── trigram_test.py├── util_test.py└── word_error_test.py3.2 運行examples
源碼中examples文件夾中放置了大量的demo,我們可以首先我們先運行幾個demo測試下效果。
3.2.1 運行base_demo.py文件
代碼很簡單,調用了pycorrector.correct方法進行糾錯,入參是待糾錯的語句,輸出是原句和出錯的詞以及糾正的詞,和具體位置。
import syssys.path.append("..")import pycorrectorpycorrector.set_log_level('INFO') if __name__ == '__main__':corrected_sent, detail = pycorrector.correct('少先隊員因該為老人讓坐')print(corrected_sent, detail)第一次運行,講下載預設的語料,大概需要10分鐘
下載完之后,講可以進行語義糾錯,如下圖,因該->應該,坐標在第4位到第6位,同理,另外一個坐->座,坐標在第10位到第11位。
接下來,讀一讀代碼,理一理邏輯。
4. 代碼詳解:
項目源碼位于pycorrector/pycorrector文件夾中
. ├── bert ├── config.py ├── conv_seq2seq ├── corrector.py ├── data ├── deep_context ├── detector.py ├── en_spell.py ├── seq2seq_attention ├── transformer ├── utils └── version.py4.1 傳統規則模型
模型代碼對應于如下三個文件:
. ├── corrector.py ├── detector.py └── en_spell.py| corrector.py | 拼寫和筆畫糾正 |
| detector.py | 錯誤詞檢測器 |
| en_spell.py | 英語糾正 |
4.1.1 錯誤詞檢測器(Detector)
4.1.1.1 代碼結構介紹
detector.py中包含一個Detector類,通過初始化這個類,來獲得實例,進行錯誤詞的檢測。如圖所示,初始化的時候,我們可以設置很多配置文件的路徑,比如停用詞文件(stopwords_path)和自定義詞頻文件(custom_word_freq_path)等。
Detector類的基礎關系如下圖所示:
其中Object是基類,提供常用的類方法:
Detector繼承了Object類,并且實現了錯詞檢測的基本方法,如下圖所示:
4.1.1.2 錯詞檢測類實例化
當去實例化Detector類的時候,只會保存一些基本諸如文件路徑和配置參數的值,并不會立即加載模型進行初始化。
class Detector(object):pre_trained_language_models = {# 語言模型 2.95GB'zh_giga.no_cna_cmn.prune01244.klm': 'https://deepspeech.bj.bcebos.com/zh_lm/zh_giga.no_cna_cmn.prune01244.klm',# 人民日報訓練語言模型 20MB'people_chars_lm.klm': 'https://www.borntowin.cn/mm/emb_models/people_chars_lm.klm'}def __init__(self, language_model_path=config.language_model_path,word_freq_path=config.word_freq_path,custom_word_freq_path=config.custom_word_freq_path,custom_confusion_path=config.custom_confusion_path,person_name_path=config.person_name_path,place_name_path=config.place_name_path,stopwords_path=config.stopwords_path):self.name = 'detector'self.language_model_path = language_model_pathself.word_freq_path = word_freq_pathself.custom_word_freq_path = custom_word_freq_pathself.custom_confusion_path = custom_confusion_pathself.person_name_path = person_name_pathself.place_name_path = place_name_pathself.stopwords_path = stopwords_pathself.is_char_error_detect = Trueself.is_word_error_detect = Trueself.initialized_detector = Falseself.lm = Noneself.word_freq = Noneself.custom_confusion = Noneself.custom_word_freq = Noneself.person_names = Noneself.place_names = Noneself.stopwords = Noneself.tokenizer = None4.1.1.2 錯詞檢測類初始化
初始化操作被放到_initialize_detector函數中,通過check_detector_initialized來判斷是否需要進行初始化。
def _initialize_detector(self):t1 = time.time()try:import kenlmexcept ImportError:raise ImportError('pycorrector dependencies are not fully installed, ''they are required for statistical language model.''Please use "pip install kenlm" to install it.''if you are Win, Please install kenlm in cgwin.')if not os.path.exists(self.language_model_path):filename = self.pre_trained_language_models.get(self.language_model_path,'zh_giga.no_cna_cmn.prune01244.klm')url = self.pre_trained_language_models.get(filename)get_file(filename, url, extract=True,cache_dir=config.USER_DIR,cache_subdir=config.USER_DATA_DIR,verbose=1)self.lm = kenlm.Model(self.language_model_path)t2 = time.time()logger.debug('Loaded language model: %s, spend: %.3f s.' % (self.language_model_path, t2 - t1))# 詞、頻數dictself.word_freq = self.load_word_freq_dict(self.word_freq_path)# 自定義混淆集self.custom_confusion = self._get_custom_confusion_dict(self.custom_confusion_path)# 自定義切詞詞典self.custom_word_freq = self.load_word_freq_dict(self.custom_word_freq_path)self.person_names = self.load_word_freq_dict(self.person_name_path)self.place_names = self.load_word_freq_dict(self.place_name_path)self.stopwords = self.load_word_freq_dict(self.stopwords_path)# 合并切詞詞典及自定義詞典self.custom_word_freq.update(self.person_names)self.custom_word_freq.update(self.place_names)self.custom_word_freq.update(self.stopwords)self.word_freq.update(self.custom_word_freq)self.tokenizer = Tokenizer(dict_path=self.word_freq_path, custom_word_freq_dict=self.custom_word_freq,custom_confusion_dict=self.custom_confusion)t3 = time.time()logger.debug('Loaded dict file, spend: %.3f s.' % (t3 - t2))self.initialized_detector = Truedef check_detector_initialized(self):if not self.initialized_detector:self._initialize_detector()4.1.1.3 初始化調用
當進行模型或者自定義詞表等設置的開頭,都會調用check_detector_initialized進行初始化設置的檢測,進行配置文件的加載。
在進行n元文分數計算和詞頻統計時候,也先檢測是否初始化。
另外在核心功能,錯詞檢測的時候,均會進行初始化:
4.1.1.4 錯詞檢測
當進行錯詞檢測的時候,先拿到實例化后的對象,然后調用detect類方法進行檢測。
detect類方法中,入參為待檢測文本,然后將依次序進行如下處理:
然后對于每個短句,調用detect_short方法進行錯詞檢測,然后會依次對短文本進行錯詞搜索。
搜索分3種,依次進行。
混淆集匹配
直接在句子中遍歷是否在混淆集中有出現,出現則直接添加到錯誤列表中。嚴格的匹配邏輯,可以通過修改混淆集文件,進行詞的添加刪除。
詞級別搜索
依次進行切詞,然后遍歷每個詞,若詞不在詞典中,也認為是錯誤。這類詞包括一些實體,一些錯詞,一些沒有在詞典中出現過,但是是正確的詞等。這條規則比較嚴格,錯詞不放過,但是也錯殺了一些其他正確詞。但是優點同第一,可以靈活修改詞典。因此,這步需要一個好的預先構造的詞典。
字級別搜索
與詞級別搜索不同,字級別不需要進行切詞,依次進行打分。分數由一個基于人民日報語料預訓練好的語言模型得出。
具體計算步驟如下:
根據每個字的平均得分列表,找到可能的錯誤字的位置(self._get_maybe_error_index);因此,這里要考慮找錯的具體邏輯。代碼中的實現是基于類似平均絕對離差(MAD)的統計概念,這里也是一個策略上的改進的方向,甚至多種策略的共同組合判斷。
其中MAD的計算如下:
代碼中的實際計算不同與上述方式,以代碼實現為主。這里可以抽象出的一個問題是:輸入是一個得分列表,輸出是錯誤位置。能否通過learning的方式獲得一個最優策略。
最后的結果是上述三種情況的并集。
接下來就是候選集的構造了(self.generate_items)。分情況討論如下:
第一種情況:confusion,如果是自定義混淆集中的錯誤,直接修改為對應的正確的值就可以了。
第二種情況:對于word和char兩種情況,沒有對應的正確的值,就需要通過語言模型來從候選集中找了。
候選集的構造邏輯如下,輸入是item,也就是檢錯階段得到的可能的錯誤詞。首先,同音字和形近字表共同可以構建一個基于字的混淆集(confusion_char_set)。其次,借助于常用字表和item之間的編輯距離,可以構建一個比較粗的候選詞集,通過常用詞表可以做一個過濾,最后加上同音的限制條件,可以得到一個更小的基于詞的混淆集(confusion_word_set)。最后,還有一個自定義的混淆集(confusion_custom _set)。
有了上述的表,就可以構建候選集了。通過候選詞的長度來分情況討論:
第一:長度為1。直接利用基于字的混淆集來替換。
第二:長度為2。分別替換每一個字。
第三:長度為3。同上。
最后,合并所有的候選集。那么通過上述的構造過程,可能導致一些無效詞或者字的出現,因此要做一些過濾處理,最后按照選出一些候選集的子集來處理。代碼中的規則是基于詞頻來處理,選擇topk個詞作為候選集。
4.1.2 拼寫和筆畫糾正(Corrector)
源碼中通過corrector.py中定義的Corrector類來完成拼寫糾錯,通過初始化這個類,來獲得實例,進行糾正。如圖所示,初始化的時候,我們可以設置很多配置文件的路徑,比如停用詞文件(stopwords_path)和自定義詞頻文件(custom_word_freq_path)等。
類初始化
同樣,Corrector類實例化的時候,也可以自定義詞頻文件,停用詞等基本信息,通過修改這些配置文件,來適應自己的業務場景。
繼承關系
Corrector的集成關系如下圖,Corrector繼承了上文中介紹的Detector類,能夠完成一些基本的長句切分,錯詞檢測功能。
示例代碼
通過源碼中給到的Demo,我們來了解下該功能的調用。通過獲取到Corrector示例,調用correct方法進行檢測:
首先import的時候會首先調用__ini__.py,在這個文件中會對必要的工具類進行初始化
然后將調用correct方法進行句子改錯
4.1.3 英文檢測
英文拼寫糾錯被作者發在了另外一個類中EnSpell,通過加載一個很大的英文語料來進行英文糾錯,具體細節將在下文闡述。
源碼示例
首先,我們通過源碼的例子來了解如何使用,如圖所示,當我們實例化EnSpell之后,直接調用en_correct方法即可對傳入的單詞進行糾錯。
繼承關系
從繼承關系可以了解到,EnSpell并未和上文講到的兩個模塊有任何關系,是一個獨立的模塊。
代碼詳解
糾錯主入口是correct方法,返回最大概率的候選.
問題來了:
- 候選值怎么確定?
- 概率怎么確定?
候選值生成
首先,通過candidates方法獲得可能的正確地拼寫詞,獲取編輯距離1,2內的候選值以及當前值和子集。
編輯距離詞的構建方法以及詞的過濾,可以參考作者的源碼實現,這里將不再贅述。
然后依次遍歷單詞中的每個字母,篩選出存在于WORDS字典中的詞。
WORDS是我們開頭講到的那個超大英文語料的詞頻字典。
概率計算
概率計算通過調用probability方法進行計算,
計算方法是使用當前詞的頻率/總得詞頻數量,十分簡單粗暴。
4.2 深度學習模型
4.2.1 Seq2Seq Attention模型
Seq2Seq基本結構
Encoder代碼實現
Decoder代碼實現
使用BahdanauAttention
下圖是不同Attention的區別,還有很多種類的Attention,本文不再贅述
代碼實現
Seq2Seq Attention訓練
訓練很簡單,代碼作者都已經寫好,只需要按上面步驟安裝好必要的環境,然后再seq2seq_attention路徑下,創建output文件夾,然后將訓練集命名為train.txt 、測試命名為test.txt。
數據集路徑
數據集結構
每一行包括一個樣本信息,包括兩部分信息,輸入數據X和標簽Y,使用\t進行分割,X和Y均為切詞后的句子,詞之間用空格分隔。
訓練
數據整理好后,之間運行train.py即可進行訓練
當模型訓練完之后,會保存模型,并且進行預測。到這里,模型的訓練就跑通了,若要使用該模型,只需要將測試數據處理成train.txt 和test.txt相同的格式,然后訓練多輪,即可得到較好的結果。
4.2.2 transformer模型
同樣,transformer模型的使用也和上文Seq2Seq Attention類似。只是數據格式稍有變化。transformer本文將不再贅述,可以參考文后留下的參考資料。
數據集結構
使用NLPCC2018比賽數據集進行訓練,該數據格式是原始文本,未做切詞處理。同樣在路徑下創建output文件夾,命名為data.train,在運行train.py的時候,會自動去切分輸入數據和標簽數據,并且構建輸入輸出的vocab。
訓練transformer
直接運行train方法即可進行訓練,訓練過程較長。
訓練過程中,會打印loss和學習率的變化,學習率會先增加,后減小,是由于transformer使用了變化的學習率,具體可以參考官網的示例。
作者還提供幾個其他模型,使用方法類似,本文就不再贅述了。
參考
總結
以上是生活随笔為你收集整理的【深度学习】PyCorrector中文文本纠错实战的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: [css] 你有没有使用过“形似猫头鹰
- 下一篇: 偏微分方程数值解法pdf_天生一对,硬核