pycorrector
https://github.com/shibing624/pycorrector
中文文本纠错工具。音似、形似错字(或变体字)纠正,可用于中文拼音、笔画输入法的错误纠正。python3开发。
pycorrector依据语言模型检测错别字位置,通过拼音音似特征、笔画五笔编辑距离特征及语言模型困惑度特征纠正错别字。
Guide
Question
中文文本纠错任务,常见错误类型包括:
- 谐音字词,如 配副眼睛-配副眼镜
- 混淆音字词,如 流浪织女-牛郎织女
- 字词顺序颠倒,如 伍迪艾伦-艾伦伍迪
- 字词补全,如 爱有天意-假如爱有天意
- 形似字错误,如 高梁-高粱
- 中文拼音全拼,如 xingfu-幸福
- 中文拼音缩写,如 sz-深圳
- 语法错误,如 想象难以-难以想象
当然,针对不同业务场景,这些问题并不一定全部存在,比如输入法中需要处理前四种,搜索引擎需要处理所有类型,语音识别后文本纠错只需要处理前两种,
其中’形似字错误’主要针对五笔或者笔画手写输入等。本项目重点解决其中的谐音、混淆音、形似字错误、中文拼音全拼、语法错误带来的纠错任务。
Solution
规则的解决思路
- 中文纠错分为两步走,第一步是错误检测,第二步是错误纠正;
- 错误检测部分先通过结巴中文分词器切词,由于句子中含有错别字,所以切词结果往往会有切分错误的情况,这样从字粒度和词粒度两方面检测错误,
整合这两种粒度的疑似错误结果,形成疑似错误位置候选集; - 错误纠正部分,是遍历所有的疑似错误位置,并使用音似、形似词典替换错误位置的词,然后通过语言模型计算句子困惑度,对所有候选集结果比较并排序,得到最优纠正词。
PS:网友源码解读
深度模型的解决思路
- 端到端的深度模型可以避免人工提取特征,减少人工工作量,RNN序列模型对文本任务拟合能力强,rnn_attention在英文文本纠错比赛中取得第一名成绩,证明应用效果不错;
- CRF会计算全局最优输出节点的条件概率,对句子中特定错误类型的检测,会根据整句话判定该错误,阿里参赛2016中文语法纠错任务并取得第一名,证明应用效果不错;
- Seq2Seq模型是使用Encoder-Decoder结构解决序列转换问题,目前在序列转换任务中(如机器翻译、对话生成、文本摘要、图像描述)使用最广泛、效果最好的模型之一;
- BERT/ELECTRA/ERNIE/MacBERT等预训练模型强大的语言表征能力,对NLP届带来翻天覆地的改变,海量的训练数据拟合的语言模型效果无与伦比,基于其MASK掩码的特征,可以简单改造预训练模型用于纠错,加上fine-tune,效果轻松达到最优。
Feature
模型
- kenlm:kenlm统计语言模型工具,规则方法,语言模型纠错,利用混淆集,扩展性强
- deep_context模型:参考Stanford University的nlc模型,该模型是参加2014英文文本纠错比赛并取得第一名的方法
- Seq2Seq模型:在Seq2Seq模型加上attention机制,对于长文本效果更好,模型更容易收敛,但容易过拟合
- ConvSeq2Seq模型:基于Facebook出品的fairseq,北京语言大学团队改进ConvS2S模型用于中文纠错,在NLPCC-2018的中文语法纠错比赛中,是唯一使用单模型并取得第三名的成绩
- transformer模型:全attention的结构代替了lstm用于解决sequence to sequence问题,语义特征提取效果更好
- BERT模型:中文fine-tuned模型,使用MASK特征纠正错字
- ELECTRA模型:斯坦福和谷歌联合提出的一种更具效率的预训练模型,学习文本上下文表示优于同等计算资源的BERT和XLNet
- ERNIE模型:百度公司提出的基于知识增强的语义表示模型,有可适配中文的强大语义表征能力。在情感分析、文本匹配、自然语言推理、词法分析、阅读理解、智能问答等16个公开数据集上超越世界领先技术
- MacBERT模型:来自哈工大SCIR实验室2020年的工作,改进了BERT模型的训练方法,使用全词掩蔽和N-Gram掩蔽策略适配中文表达,和通过用其相似的单词来掩盖单词,从而缩小训练前和微调阶段之间的差距
错误检测
- 字粒度:语言模型困惑度(ppl)检测某字的似然概率值低于句子文本平均值,则判定该字是疑似错别字的概率大。
- 词粒度:切词后不在词典中的词是疑似错词的概率大。
错误纠正
- 通过错误检测定位所有疑似错误后,取所有疑似错字的音似、形似候选词,
- 使用候选词替换,基于语言模型得到类似翻译模型的候选排序结果,得到最优纠正词。
思考
- 现在的处理手段,在词粒度的错误召回还不错,但错误纠正的准确率还有待提高,更多优质的纠错集及纠错词库会有提升,我更希望算法上有更大的突破。
- 另外,现在的文本错误不再局限于字词粒度上的拼写错误,需要提高中文语法错误检测(CGED, Chinese Grammar Error Diagnosis)及纠正能力,列在TODO中,后续调研。
Demo
http://42.193.145.218/product/corrector/
Evaluate
查看评估结论
提供评估脚本pycorrector/utils/eval.py和评估执行脚本examples/evaluate_models.py,该脚本有两个功能:
- 构建评估样本集:评估集pycorrector/data/eval_corpus.json, 包括字粒度错误100条、词粒度错误100条、语法错误100条,正确句子200条。用户可以修改条数生成其他评估样本分布。
- 计算两个数据集的纠错准召率:采用保守计算方式,简单把纠错之后与正确句子完成匹配的视为正确,否则为错。
测试环境:
- 机器:linux(centos7) 线上机
- CPU:28核 Intel® Xeon® Gold 5117 CPU @ 2.00GHz
- GPU:Tesla P40,显存 22919 MiB(22 GB)
- 内存:251 GB
数据集 | 模型 | cpu/gpu | 准确率 | 召回率 | 每百条预测时长(秒) | QPS |
---|---|---|---|---|---|---|
sighan_15 | rule | cpu | 17.98% | 15.37% | 11 | 9 |
sighan_15 | bert | gpu | 37.62% | 36.46% | 95 | 1.05 |
sighan_15 | ernie | gpu | 29.70% | 28.13% | 102 | 0.98 |
sighan_15 | macbert | gpu | 63.64% | 63.64% | 2 | 50 |
corpus500 | rule | cpu | 48.60% | 28.13% | 11 | 9 |
corpus500 | bert | gpu | 58.60% | 35.00% | 95 | 1.05 |
corpus500 | ernie | gpu | 59.80% | 41.33% | 102 | 0.98 |
corpus500 | macbert | gpu | 56.20% | 42.67% | 2 | 50 |
Install
- 全自动安装:pip install pycorrector
- 半自动安装:
git clone https://github.com/shibing624/pycorrector.git
cd pycorrector
python setup.py install
通过以上两种方法的任何一种完成安装都可以。如果不想安装依赖包,直接使用docker拉取安装好的部署环境即可。
安装依赖
- docker使用
docker run -it -v ~/.pycorrector:/root/.pycorrector shibing624/pycorrector:0.0.2
后续调用python3使用即可,该镜像已经安装好kenlm、pycorrector等包,具体参见Dockerfile。
使用示例:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2ngSbsRv-1636205742536)(docs/git_image/docker.png)]
- kenlm安装
pip install https://github.com/kpu/kenlm/archive/master.zip
- 其他库包安装
pip install -r requirements.txt
Usage
- 文本纠错
import pycorrector
corrected_sent, detail = pycorrector.correct('少先队员因该为老人让坐')
print(corrected_sent, detail)
output:
少先队员应该为老人让座 [('因该', '应该', 4, 6), ('坐', '座', 10, 11)]
规则方法默认会从路径
~/.pycorrector/datasets/zh_giga.no_cna_cmn.prune01244.klm
加载kenlm语言模型文件,如果检测没有该文件,则程序会自动联网下载。当然也可以手动下载模型文件(2.8G)并放置于该位置。
查看更多使用说明
- 错误检测
import pycorrector
idx_errors = pycorrector.detect('少先队员因该为老人让坐')
print(idx_errors)
output:
[['因该', 4, 6, 'word'], ['坐', 10, 11, 'char']]
返回类型是
list
,[error_word, begin_pos, end_pos, error_type]
,pos
索引位置以0开始。
- 关闭字粒度纠错
import pycorrector
error_sentence_1 = '我的喉咙发炎了要买点阿莫细林吃'
correct_sent = pycorrector.correct(error_sentence_1)
print(correct_sent)
output:
'我的喉咙发炎了要买点阿莫西林吉', [('细林', '西林', 12, 14), ('吃', '吉', 14, 15)]
上例中吃
发生误纠,如下代码关闭字粒度纠错:
import pycorrector
error_sentence_1 = '我的喉咙发炎了要买点阿莫细林吃'
pycorrector.enable_char_error(enable=False)
correct_sent = pycorrector.correct(error_sentence_1)
print(correct_sent)
output:
'我的喉咙发炎了要买点阿莫西林吃', [('细林', '西林', 12, 14)]
默认字粒度、词粒度的纠错都打开,一般情况下单字错误发生较少,而且字粒度纠错准确率较低。关闭字粒度纠错,这样可以提高纠错准确率,提高纠错速度。
默认
enable_char_error
方法的enable
参数为True
,即打开错字纠正,这种方式可以召回字粒度错误,但是整体准确率会低;
如果追求准确率而不追求召回率的话,建议将
enable
设为False
,仅使用错词纠正。
- 加载自定义混淆集
通过加载自定义混淆集,支持用户纠正已知的错误,包括两方面功能:1)错误补召回;2)误杀加白。
import pycorrector
pycorrector.set_log_level('INFO')
error_sentences = [
'买iphonex,要多少钱',
'共同实际控制人萧华、霍荣铨、张旗康',
]
for line in error_sentences:
print(pycorrector.correct(line))
print('*' * 42)
pycorrector.set_custom_confusion_dict(path='./my_custom_confusion.txt')
for line in error_sentences:
print(pycorrector.correct(line))
output:
('买iphonex,要多少钱', []) # "iphonex"漏召,应该是"iphoneX"
('共同实际控制人萧华、霍荣铨、张启康', [['张旗康', '张启康', 14, 17]]) # "张启康"误杀,应该不用纠
*****************************************************
('买iphonex,要多少钱', [['iphonex', 'iphoneX', 1, 8]])
('共同实际控制人萧华、霍荣铨、张旗康', [])
具体demo见example/use_custom_confusion.py,其中./my_custom_confusion.txt
的内容格式如下,以空格间隔:
iPhone差 iPhoneX 100
张旗康 张旗康
set_custom_confusion_dict
方法的path
参数为用户自定义混淆集文件路径。
- 加载自定义语言模型
默认提供下载并使用的kenlm语言模型zh_giga.no_cna_cmn.prune01244.klm
文件是2.8G,内存较小的电脑使用pycorrector
程序可能会吃力些。
支持用户加载自己训练的kenlm语言模型,或使用2014版人民日报数据训练的模型,模型小(140M),准确率低些。
示例load_custom_language_model.py,其中people2014corpus_chars.klm(密码o5e9)是自定义语言模型文件。
from pycorrector import Corrector
import os
pwd_path = os.path.abspath(os.path.dirname(__file__))
lm_path = os.path.join(pwd_path, './people2014corpus_chars.klm')
model = Corrector(language_model_path=lm_path)
corrected_sent, detail = model.correct('少先队员因该为老人让坐')
print(corrected_sent, detail)
output:
少先队员应该为老人让座 [('因该', '应该', 4, 6), ('坐', '座', 10, 11)]
- 英文拼写纠错
支持英文单词的拼写错误纠正。
import pycorrector
sent = "what happending? how to speling it, can you gorrect it?"
corrected_text, details = pycorrector.en_correct(sent)
print(sent, '=>', corrected_text)
print(details)
output:
what happending? how to speling it, can you gorrect it?
=> what happening? how to spelling it, can you correct it?
[('happending', 'happening', 5, 15), ('speling', 'spelling', 24, 31), ('gorrect', 'correct', 44, 51)]
- 中文简繁互换
支持中文繁体到简体的转换,和简体到繁体的转换。
示例traditional_simplified_chinese_demo.py
import pycorrector
traditional_sentence = '憂郁的臺灣烏龜'
simplified_sentence = pycorrector.traditional2simplified(traditional_sentence)
print(traditional_sentence, '=>', simplified_sentence)
simplified_sentence = '忧郁的台湾乌龟'
traditional_sentence = pycorrector.simplified2traditional(simplified_sentence)
print(simplified_sentence, '=>', traditional_sentence)
output:
憂郁的臺灣烏龜 => 忧郁的台湾乌龟
忧郁的台湾乌龟 => 憂郁的臺灣烏龜
- 命令行模式
支持批量文本纠错
python -m pycorrector -h
usage: __main__.py [-h] -o OUTPUT [-n] [-d] input
@description:
positional arguments:
input the input file path, file encode need utf-8.
optional arguments:
-h, --help show this help message and exit
-o OUTPUT, --output OUTPUT
the output file path.
-n, --no_char disable char detect mode.
-d, --detail print detail info
case:
python -m pycorrector input.txt -o out.txt -n -d
输入文件:
input.txt
;输出文件:out.txt
;关闭字粒度纠错;打印详细纠错信息;纠错结果以\t
间隔
Deep Model Usage
安装依赖
pip install -r requirements-dev.txt
介绍
本项目的初衷之一是比对、共享各种文本纠错方法,抛砖引玉的作用,如果对大家在文本纠错任务上有一点小小的启发就是我莫大的荣幸了。
主要使用了多种深度模型应用于文本纠错任务,分别是前面模型
小节介绍的seq2seq、
transformer、bert、macbert、electra,各模型方法内置于pycorrector
文件夹下,有README.md
详细指导,各模型可独立运行,相互之间无依赖。
使用方法
各模型均可独立的预处理数据、训练、预测。
- MacBert模型
基于MacBert预训练模型的纠错
示例macbert_demo.py,详细教程参考README
- 模型下载
下载fine-tune后的预训练MacBert MLM模型-密码QKz3,解压后放置于~/.pycorrector/dataset/macbert_models/chinese_finetuned_correction
目录下。
macbert_models
└── chinese_finetuned_correction
├── config.json
├── added_tokens.json
├── pytorch_model.bin
├── special_tokens_map.json
├── tokenizer_config.json
└── vocab.txt
- 纠错
import sys
sys.path.append("..")
from pycorrector.macbert.macbert_corrector import MacBertCorrector
if __name__ == '__main__':
error_sentences = [
'真麻烦你了。希望你们好好的跳无',
'少先队员因该为老人让坐',
'机七学习是人工智能领遇最能体现智能的一个分知',
'一只小鱼船浮在平净的河面上',
'我的家乡是有明的渔米之乡',
]
m = MacBertCorrector()
for line in error_sentences:
correct_sent, err = m.macbert_correct(line)
print("query:{} => {}, err:{}".format(line, correct_sent, err))
output:
query:真麻烦你了。希望你们好好的跳无 => 真麻烦你了。希望你们好好的跳舞, err:[('无', '舞', 14, 15)]
query:少先队员因该为老人让坐 => 少先队员应该为老人让坐, err:[('因', '应', 4, 5)]
query:机七学习是人工智能领遇最能体现智能的一个分知 => 机器学习是人工智能领域最能体现智能的一个分知, err:[('七', '器', 1, 2), ('遇', '域', 10, 11)]
query:一只小鱼船浮在平净的河面上 => 一只小鱼船浮在平净的河面上, err:[]
query:我的家乡是有明的渔米之乡 => 我的家乡是有名的渔米之乡, err:[('明', '名', 6, 7)]
查看Seq2Seq模型
- Seq2Seq模型
seq2seq 模型使用示例:
配置
通过修改config.py
。
数据预处理
cd seq2seq
# 数据预处理
python preprocess.py
自动新建文件夹output,在output下生成train.txt
和test.txt
文件,以TAB(”\t”)间隔错误文本和纠正文本,文本以空格切分词,文件内容示例:
希 望 少 吸 烟 。 希 望 烟 民 们 少 吸 烟 。
以 前 , 包 括 中 国 , 我 国 也 是 。 以 前 , 不 仅 中 国 , 我 国 也 是 。
我 现 在 好 得 多 了 。 我 现 在 好 多 了 。
训练
python train.py
设置config.py
中arch='convseq2seq'
,训练sighan数据集(2104条样本),200个epoch,单卡P40GPU训练耗时:3分钟。
预测
python infer.py
预测输出效果样例截图:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ptmhIWA3-1636205742537)(./docs/git_image/convseq2seq_ret.png)]
PS:
- 如果训练数据太少(不足万条),深度模型拟合不足,会出现预测结果全为
unk
的情况,解决方法:增大训练样本集,使用下方提供的纠错熟语料(nlpcc2018+hsk,130万对句子)测试。 - 深度模型训练耗时长,有GPU尽量用GPU,加速训练,节省时间。
Dataset
数据集 | 语料 | 下载链接 | 压缩包大小 |
---|---|---|---|
人民日报2014版语料 | 人民日报2014版 | 百度网盘(密码uc11) 飞书(密码cHcu) | 383M |
NLPCC 2018 GEC官方数据集 | NLPCC2018-GEC | 官方trainingdata | 114M |
NLPCC 2018+HSK熟语料 | nlpcc2018+hsk+CGED | 百度网盘(密码m6fg) 飞书(密码gl9y) | 215M |
NLPCC 2018+HSK原始语料 | HSK+Lang8 | 百度网盘(密码n31j) 飞书(密码Q9LH) | 81M |
- NLPCC 2018 GEC官方数据集NLPCC2018-GEC,
训练集trainingdata[解压后114.5MB],该数据格式是原始文本,未做切词处理。 - 汉语水平考试(HSK)和lang8原始平行语料[HSK+Lang8]百度网盘(密码n31j),该数据集已经切词,可用作数据扩增
- 以上语料,再加上CGED16、CGED17、CGED18的数据,经过以字切分,繁体转简体,打乱数据顺序的预处理后,生成用于纠错的熟语料(nlpcc2018+hsk),网盘链接:https://pan.baidu.com/s/1BkDru60nQXaDVLRSr7ktfA 密码:m6fg [130万对句子,215MB]
Custom Language Model
语言模型对于纠错步骤至关重要,当前默认使用的是从千兆中文文本训练的中文语言模型zh_giga.no_cna_cmn.prune01244.klm(2.8G),
此处也提供人民日报2014版语料训练得到的轻量版语言模型people2014corpus_chars.klm(密码o5e9)。
大家可以用中文维基(繁体转简体,pycorrector.utils.text_utils下有此功能)等语料数据训练通用的语言模型,或者也可以用专业领域语料训练更专用的语言模型。更适用的语言模型,对于纠错效果会有比较好的提升。
- kenlm语言模型训练工具的使用,请见博客:http://blog.csdn.net/mingzai624/article/details/79560063
- 附上训练语料<人民日报2014版熟语料>,包括:
1)标准人工切词及词性数据people2014.tar.gz,
2)未切词文本数据people2014_words.txt,
3)kenlm训练字粒度语言模型文件及其二进制文件people2014corpus_chars.arps/klm,
4)kenlm词粒度语言模型文件及其二进制文件people2014corpus_words.arps/klm。
尊重版权,传播请注明出处。
Todo
- 优化形似字字典,提高形似字纠错准确率
- 整理中文纠错训练数据,使用seq2seq做深度中文纠错模型
- 添加中文语法错误检测及纠正能力
- 规则方法添加用户自定义纠错集,并将其纠错优先度调为最高
- seq2seq_attention 添加dropout,减少过拟合
- 在seq2seq模型框架上,新增Pointer-generator network、Beam search、Unknown words replacement、Coverage mechanism等特性
- 更新bert的fine-tuned使用wiki,适配transformers 2.10.0库
- 升级代码,兼容TensorFlow 2.0库
- 升级bert纠错逻辑,提升基于mask的纠错效果
- 新增基于electra模型的纠错逻辑,参数更小,预测更快
- 新增专用于纠错任务深度模型,使用bert/ernie预训练模型,加入文本音似、形似特征。
- 规则方法,改进
generate_items
疑似错字生成函数,提速并优化逻辑。 - 预测提速,规则方法加入vertebi动态规划,深度模型使用beamsearch搜索结果,引入GPU + fp16预测部署。
- 语言模型纠错ppl阈值参数,使用动态调整方法替换写死的阈值。
Reference
- 基于文法模型的中文纠错系统
- Norvig’s spelling corrector
- Chinese Spelling Error Detection and Correction Based on Language Model, Pronunciation, and Shape[Yu, 2013]
- Chinese Spelling Checker Based on Statistical Machine Translation[Chiu, 2013]
- Chinese Word Spelling Correction Based on Rule Induction[yeh, 2014]
- Neural Language Correction with Character-Based Attention[Ziang Xie, 2016]
- Chinese Spelling Check System Based on Tri-gram Model[Qiang Huang, 2014]
- Neural Abstractive Text Summarization with Sequence-to-Sequence Models[Tian Shi, 2018]
- 基于深度学习的中文文本自动校对研究与实现[杨宗霖, 2019]
- A Sequence to Sequence Learning for Chinese Grammatical Error Correction[Hongkai Ren, 2018]
- ELECTRA: Pre-training Text Encoders as Discriminators Rather Than Generators
- Revisiting Pre-trained Models for Chinese Natural Language Processing