文本纠错--文本分割N-gram--Macbert模型的调用以及对返回结果的处理

news2024/11/17 13:49:54

文本根据词典进行纠错

输入一段可能带有错误信息的文字, 通过词典来检测其中可能错误的词。
例如:有句子如下:中央人民政府驻澳门特别行政区联络办公室1日在机关大楼设灵堂
   有词典如下:中国人民,中央人民,澳门,西门
   检测时,根据词典可以得出句子中的中央人民可能为中国人民,澳门可能为西门,并返回结果

处理逻辑如下:

  • 首先对词典进行逐字打码,例如中国人民处理成:*国人民,中*人民,中国*民,中国人*,并返回一个index_list记录对应的位置和打码的位置(后面才可以根据这个index_list找到候选词)。
  • 接着对句子进行N-gram,比如检测第二个字时,设置n为4(一般都处理为4),处理成:中央,中央人,中央人民,央人,央人民,央人民政,并对央打码,处理成:中*,中*人,中*人民,*人,*人民,*人民政
  • 最后与上述处理完的词典进行对比,如果找到相同的比如:词典里面的 中*人民 与 检测时返回的N-gram里面的 中*人民相同,便根据index_list找到词典中的中国人民,由此可得,字的候选词为。如下:{‘correction’: ‘国’, ‘index’: 1, ‘candidate’: [‘中国人民’], ‘original’: ‘央’}

实现代码如下:

  • 对词典进行处理:
def get_new_dict(dict):
    '''
    将词典逐字打码
    :param dict:
    :return: 新词典以及对应的index
    '''
    new_dict = []
    index_list = []
    for j in range(len(dict)):
        for i in range(len(dict[j])):
            if i < len(dict[j]):
                new_dic = dict[j][:i] + '*' + dict[j][i+1:]
            else:
                new_dic = dict[j][:i] + '*'
            new_dict.append(new_dic)
            index_list.append((j,i))
    return new_dict,index_list
#测试:
dicts = ['中国人民','中央人民','澳门','西门']
new_dict,index_list = get_new_dict(dicts)
print(new_dict)
print("**********************")
print(index_list)

输出:

index_list的元组第一个值表示词典的索引位置,第二个值表示对应这个词打码位置的索引

在这里插入图片描述

  • 对句子进行N-gram
def get_ngram(content,loc,n):
    '''
    切分Ngram.函数为根据索引位置切分,如果想切分整个content,只需要加一个循环使loc从0到len(conten)-1
    :param content: 原文
    :param loc: 想要检测的字的索引位置
    :param n: 切分长度
    :return: ngram
    '''
    i_min = loc-n+1 if loc-n+1 >= 0 else 0
    i_max = loc+1
    j_min = loc+1
    j_max = loc+1+n if loc+1+n < len(content) else loc+1+1
    ngram_list = []
    for i in range(i_min,i_max):
        for j in range(j_min,j_max):
            if j-i > 4 or j - i < 2:
                continue
            ngram_list.append(content[i:j].replace(content[loc],'*'))
    return ngram_list
#测试
content = '中央人民政府驻澳门特别行政区联络办公室1日在机关大楼设灵堂'
loc = 1
ngram_list = get_ngram(content,loc,n=4)
print(ngram_list)

输出:
在这里插入图片描述

  • 最后进行词典与N-gram的比对并返回相应结果:
def get_result(ngram_list,new_dict,index_list,loc,original,dicts):
    '''
    获取结果
    :param ngram_list: 原文分割后的Ngram
    :param new_dict: 打码处理后的字典
    :param index_list: 处理后的字典对应的索引位置
    :param loc: 检测字的索引位置
    :param original: 检测的字
    :param dicts: 原始词典
    :return:
    '''
    candidate = []
    error_dic = {}
    for word in ngram_list:
        if word in new_dict:
            indexs = [i for (i, v) in enumerate(new_dict) if v == word]
            for index in indexs:
                index = index_list[index]
                correction = dicts[index[0]][index[1]]
                if original == correction:
                    continue
                candidate.append(dicts[index[0]])
                error_dic['correction'] = correction
                error_dic['index'] = loc
                error_dic['candidate'] = candidate
                error_dic['original'] = original
    return error_dic
#测试
original = content[loc]
error_dic = get_result(ngram_list,new_dict,index_list,loc,original,dicts)
print(error_dic)

输出:

{‘correction’: ‘国’, ‘index’: 1, ‘candidate’: [‘中国人民’], ‘original’: ‘央’}

完整代码如下:

def get_ngram(content,loc,n):
    '''
    切分Ngram.函数为根据索引位置切分,如果想切分整个content,只需要加一个循环使loc从0到len(conten)-1
    :param content: 原文
    :param loc: 想要检测的字的索引位置
    :param n: 切分长度
    :return: ngram
    '''
    i_min = loc-n+1 if loc-n+1 >= 0 else 0
    i_max = loc+1
    j_min = loc+1
    j_max = loc+1+n if loc+1+n < len(content) else loc+1+1
    ngram_list = []
    for i in range(i_min,i_max):
        for j in range(j_min,j_max):
            if j-i > 4 or j - i < 2:
                continue
            ngram_list.append(content[i:j].replace(content[loc],'*'))
    return ngram_list

def get_new_dict(dict):
    '''
    将词典逐字打码
    :param dict:
    :return: 新词典以及对应的index
    '''
    new_dict = []
    index_list = []
    for j in range(len(dict)):
        for i in range(len(dict[j])):
            if i < len(dict[j]):
                new_dic = dict[j][:i] + '*' + dict[j][i+1:]
            else:
                new_dic = dict[j][:i] + '*'
            new_dict.append(new_dic)
            index_list.append((j,i))
    return new_dict,index_list


def get_result(ngram_list,new_dict,index_list,loc,original,dicts):
    '''
    获取结果
    :param ngram_list: 原文分割后的Ngram
    :param new_dict: 打码处理后的字典
    :param index_list: 处理后的字典对应的索引位置
    :param loc: 检测字的索引位置
    :param original: 检测的字
    :param dicts: 原始词典
    :return:
    '''
    candidate = []
    error_dic = {}
    for word in ngram_list:
        if word in new_dict:
            indexs = [i for (i, v) in enumerate(new_dict) if v == word]
            for index in indexs:
                index = index_list[index]
                correction = dicts[index[0]][index[1]]
                if original == correction:
                    continue
                candidate.append(dicts[index[0]])
                error_dic['correction'] = correction
                error_dic['index'] = loc
                error_dic['candidate'] = candidate
                error_dic['original'] = original
    return error_dic
#测试

#测试
dicts = ['中国人民','中央人民','澳门','西门']
content = '中央人民政府驻澳门特别行政区联络办公室1日在机关大楼设灵堂'
loc = 7
original = content[loc]
ngram_list = get_ngram(content,loc,n=4)
new_dict,index_list = get_new_dict(dicts)
error_dic = get_result(ngram_list,new_dict,index_list,loc,original,dicts)
print(error_dic)
'''
输出:
{'correction': '西', 'index': 7, 'candidate': ['西门'], 'original': '澳'}
'''

Macbert是什么?

原始 BERT 模型的缺点之一是预训练和微调阶段任务不一致,pretrain 有 [mask] 字符,而 finetune 没有。
MacBERT 用目标单词的相似单词,替代被 mask 的字符,减轻了预训练和微调阶段之间的差距。
输入一句话,给其中的字打上“mask”标记,来预测“mask”标记的地方原本是哪个字。

input: 欲把西[mask]比西子,淡[mask]浓抹总相宜
output: 欲把西[湖]比西子,淡[妆]浓抹总相宜

通过transformers使用macbert:

https://huggingface.co/hfl/chinese-macbert-base/tree/main
这是macbert的模型地址,包括词典,配置等等
在这里插入图片描述

通过pipeline调用语言模型:

pipeline有以下几种task:

task (str):
The task defining which pipeline will be returned. Currently accepted tasks are:

        - `"audio-classification"`: will return a [`AudioClassificationPipeline`].
        - `"automatic-speech-recognition"`: will return a [`AutomaticSpeechRecognitionPipeline`].
        - `"conversational"`: will return a [`ConversationalPipeline`].
        - `"feature-extraction"`: will return a [`FeatureExtractionPipeline`].
        - `"fill-mask"`: will return a [`FillMaskPipeline`]:.
        - `"image-classification"`: will return a [`ImageClassificationPipeline`].
        - `"question-answering"`: will return a [`QuestionAnsweringPipeline`].
        - `"table-question-answering"`: will return a [`TableQuestionAnsweringPipeline`].
        - `"text2text-generation"`: will return a [`Text2TextGenerationPipeline`].
        - `"text-classification"` (alias `"sentiment-analysis"` available): will return a
          [`TextClassificationPipeline`].
        - `"text-generation"`: will return a [`TextGenerationPipeline`]:.
        - `"token-classification"` (alias `"ner"` available): will return a [`TokenClassificationPipeline`].
        - `"translation"`: will return a [`TranslationPipeline`].
        - `"translation_xx_to_yy"`: will return a [`TranslationPipeline`].
        - `"summarization"`: will return a [`SummarizationPipeline`].
        - `"zero-shot-classification"`: will return a [`ZeroShotClassificationPipeline`].
#text-classification :文本分类
from transformers import pipeline
pipe = pipeline("text-classification",model='hfl/chinese-macbert-base')#模型地址
response = pipe("This restaurant is awesome")
print(response)
'''
[{'label': 'LABEL_0', 'score': 0.6576499342918396}]
'''


#fill-mask 文本填充
from transformers import pipeline
pipe = pipeline("fill-mask",model='hfl/chinese-macbert-base')
response = pipe("我爱吃[MASK]")
print(response)
'''
会输出前五个觉得可能的词替代mask的位置
[{'score': 0.31384092569351196, 'token': 511, 'token_str': '。', 'sequence': '我 爱 吃 。'}, 
{'score': 0.2933292090892792, 'token': 8013, 'token_str': '!', 'sequence': '我 爱 吃 !'}, 
{'score': 0.045837629586458206, 'token': 4638, 'token_str': '的', 'sequence': '我 爱 吃 的'}, 
{'score': 0.02681967243552208, 'token': 2124, 'token_str': '它', 'sequence': '我 爱 吃 它'}, 
{'score': 0.025146018713712692, 'token': 1557, 'token_str': '啊', 'sequence': '我 爱 吃 啊'}]
'''

直接调用模型得到结果,首先要知道传入macbert的数据应该有三个,分别是经过token emb 分词,segment emb 分句子,position emb 分句子中的位置,可以利用AutoTokenizer得到

from transformers import AutoTokenizer,TFAutoModelForMaskedLM
def get_token(filename='hfl/chinese-macbert-base'):
    '''
    创建分词器
    :param finlename:
    :return: tokenizers
    '''
    tokenizers = AutoTokenizer.from_pretrained(filename)
    return tokenizers
def get_model(filename='hfl/chinese-macbert-base'):
    '''
    构建模型
    :param filename: 模型所在位置
    :return: model
    '''
    model = TFAutoModelForMaskedLM.from_pretrained(filename)
    return model
tokenizers = get_token()
model = get_model()
content = '我爱吃饭'
token = tokenizers(content,return_tensors='tf')#设置返回格式,好传入model
output = model(token)
print(output)
  • 首先先查看一下token的数据:
    在这里插入图片描述
    可以看到传入的参数有三个,这里我们这需要第一个input_ids(会分出[CLS],[SEP],代表句子开头和结尾,并不是我们需要的数据,在后面的处理中需要过滤掉),这个input_ids是输入的content被分词后每个词对应在词典vocab.txt里面的位置(vocav.txt在模型所在的网址处,最下面一个就是),得到input_ids去词典里面找就可以得到content被分词后的情况。
  • 查看output
    在这里插入图片描述
    其中的logits的shape为(1, 6, 21128)对应的就是第一个句子,六个分词,21128个词,三维表示的意思就是这个分词在词典中对应的概率。我们可以通过上述得到的input_ids和logits对应的三维概率,根据词典来得到这个分词的替换词。
  • 完整代码如下:记得去网址下载词典并放在相应位置
from transformers import AutoTokenizer,TFAutoModelForMaskedLM
import tensorflow as tf
def get_vocab(filename='vocab.txt'):
    '''
    :param filename: 文件名称
    :return: vocab_list
    '''
    vocab_list = []
    with open(filename,'r',encoding='utf8') as fp:
        for line in fp:
            vocab_list.append(line)
    return vocab_list
def get_token(filename='hfl/chinese-macbert-base'):
    '''
    创建分词器
    :param finlename:
    :return: tokenizers
    '''
    tokenizers = AutoTokenizer.from_pretrained(filename)
    return tokenizers
def get_model(filename='hfl/chinese-macbert-base'):
    '''
    构建模型
    :param filename: 模型所在位置
    :return: model
    '''
    model = TFAutoModelForMaskedLM.from_pretrained(filename)
    return model
def get_new_word(input_ids,logits,vocab_list,top_k):
    '''
    :param input_ids: 分词后的结果
    :param logits: model返回的数据
    :param vocab_list: 词典
    :return: 存放原来词和五个替换词的字典
    '''
    result= []
    input_ids_index = 0
    for sentence in logits:
        for predict in sentence:
            new_word = []
            token = input_ids[0][input_ids_index]
            token = vocab_list[token].replace('\n', '')
            if token in ['[CLS]','[SEP]']:#分词会分出 '[CLS]','[SEP]',并不是需要的数据故不管
                input_ids_index += 1
                continue
            index_max = tf.argsort(-predict).numpy().tolist()[:top_k]
            for index in index_max:
                dic = {}
                str = vocab_list[index].replace('\n','')
                dic['correction'] = str
                dic['index'] = input_ids_index
                dic['prob'] = predict.numpy().tolist()[index]
                dic['original'] = token
                new_word.append(dic)
            result.append(new_word)
            input_ids_index += 1
    return result
if __name__ == '__main__':
    vocab_list = get_vocab()
    tokenizers = get_token()
    model = get_model()
    content = '我爱吃饭'
    token = tokenizers(content,return_tensors='tf')#设置返回格式,好传入model
    input_ids = token['input_ids'].numpy().tolist()#转成列表
    output = model(token)
    logits = tf.nn.softmax(output.logits)
    result = get_new_word(input_ids, logits, vocab_list,top_k=5)#top_k是获取前五个概率值最大的替换词
    print(result)
'''

[
[{'correction': '我', 'index': 1, 'prob': 0.49622663855552673, 'original': '我'}, 
{'correction': '也', 'index': 1, 'prob': 0.02421947941184044, 'original': '我'}, 
{'correction': '不', 'index': 1, 'prob': 0.021840188652276993, 'original': '我'}, 
{'correction': '爱', 'index': 1, 'prob': 0.01763201504945755, 'original': '我'}, 
{'correction': '你', 'index': 1, 'prob': 0.013141845352947712, 'original': '我'}], 

[{'correction': '爱', 'index': 2, 'prob': 0.7990172505378723, 'original': '爱'}, 
{'correction': '不', 'index': 2, 'prob': 0.008415293879806995, 'original': '爱'}, 
{'correction': '要', 'index': 2, 'prob': 0.007923864759504795, 'original': '爱'}, 
{'correction': '是', 'index': 2, 'prob': 0.0068937744945287704, 'original': '爱'}, 
{'correction': '想', 'index': 2, 'prob': 0.0060282074846327305, 'original': '爱'}], 

[{'correction': '吃', 'index': 3, 'prob': 0.4919191598892212, 'original': '吃'}, 
{'correction': '的', 'index': 3, 'prob': 0.03245647996664047, 'original': '吃'}, 
{'correction': '你', 'index': 3, 'prob': 0.0290437750518322, 'original': '吃'}, 
{'correction': '有', 'index': 3, 'prob': 0.021838273853063583, 'original': '吃'}, 
{'correction': '我', 'index': 3, 'prob': 0.017963092774152756, 'original': '吃'}],
 
[{'correction': '!', 'index': 4, 'prob': 0.10435411334037781, 'original': '饭'}, 
{'correction': '。', 'index': 4, 'prob': 0.07520557194948196, 'original': '饭'}, 
{'correction': '啊', 'index': 4, 'prob': 0.06121807172894478, 'original': '饭'}, 
{'correction': '?', 'index': 4, 'prob': 0.04430496692657471, 'original': '饭'}, 
{'correction': '吗', 'index': 4, 'prob': 0.029895102605223656, 'original': '饭'}]
]
'''

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/78128.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

漏斗分析 - AARRR模型案例分析

漏斗分析是一套流程式的数据分析方法&#xff0c;能够科学地反映各阶段用户转化情况。漏斗分析模型已经广泛应用于用户行为分析类产品&#xff0c;且功能十分强大&#xff1a;它可以评估总体或各个环节的转化情况、促销活动效果&#xff1b;也可以与其他数据分析模型结合进行深…

【三维目标检测】SSN(二)

SSN数据和源码配置调试过程请参考上一篇博文&#xff1a;【三维目标检测】SSN&#xff08;一&#xff09;_Coding的叶子的博客-CSDN博客。本文主要详细介绍SSN网络结构及其运行中间状态。 1 模型总体过程 SSN主要结构如下图所示&#xff0c;其核心在于提出了shape-aware heads…

认识分布式锁、使用分布式锁 Redission、实现秒杀案例

分布式锁 基本原理 分布式锁&#xff1a;满足分布式系统或集群模式下多进程可见并且互斥的锁。 分布式锁的核心思想就是让大家都使用同一把锁&#xff0c;只要大家使用的是同一把锁&#xff0c;那么我们就能锁住线程&#xff0c;不让线程进行&#xff0c;让程序串行执行&…

[附源码]计算机毕业设计基于Vue的社区拼购商城Springboot程序

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

node.js-fs模块学习

目录 1.使用fs.readFile方法读取文件 2.使用fs.writeFile方法写入文件 3.fs小案例-整理成绩并写入到新文件中 4.fs模块-路径动态拼接的问题 1.使用fs.readFile方法读取文件 //导入fs模块 const fs require(fs)//调用fs读取文件 //参数1&#xff1a;读取文件的存放路径 //…

spring——Spring Bean属性注入——短命名空间注入——p 命名空间注入(setter注入)...

短命名空间注入 我们在通过构造函数或 setter 方法进行属性注入时&#xff0c;通常是在 <bean> 元素中嵌套 <property> 和 <constructor-arg> 元素来实现的。这种方式虽然结构清晰&#xff0c;但书写较繁琐。Spring 框架提供了 2 种短命名空间&#xff0c;可…

java基于Springboot的论坛管理系统-计算机毕业设计

项目介绍 在社会快速发展的影响下&#xff0c;论坛管理系统继续发展&#xff0c;使论坛管理系统的管理和运营比过去十年更加信息化。依照这一现实为基础&#xff0c;设计一个快捷而又方便的网上论坛管理系统是一项十分重要并且有价值的事情。对于传统的论坛管理系统控制模型来…

【大数据入门核心技术-Azkaban】(一)Azkaban介绍

目录 一、Azkaban 是什么 二、Azkaban 特点 三、Azkaban 与 Oozie 对比 一、Azkaban 是什么 Azkaban 是由 Linkedin 公司推出的一个批量工作流任务调度器&#xff0c;Azkaban 使用 job 文件建立任务之间的依赖关系&#xff0c;并提供 Web 界面供用户管理和调度工作流 官方网…

最新、最全面的Java面试题及答案(212道)

文章目录一. Java 基础1. JDK 和 JRE 有什么区别&#xff1f;2. 和 equals 的区别是什么&#xff1f;3. 两个对象的 hashCode() 相同&#xff0c;则equals() 也一定为true&#xff0c;对吗&#xff1f;4. final 在 Java 中有什么作用&#xff1f;5. Java 中的 Math. round(-1.…

服务器编译spark3.3.1源码支持CDH6.3.2

1、一定要注意编译环境的配置 mvn:3.6.3 scala:2.12.17 JDK:1.8 spark:3.3.1 服务器内存至少需要 8G 重点2、下载连接 wget https://dlcdn.apache.org/maven/maven-3/3.6.3/binaries/apache-maven-3.6.3-bin.zip wget https://downloads.lightbend.com/scala/2.12.17/scala-2…

大量域名数据下载地址收集整理

说明地址中文网站排行榜——网站排名大全http://www.alexa.cn/siterankAlexa排名(70万的数据)top-1m.csv.zipCisco Umbrellahttp://s3-us-west-1.amazonaws.com/umbrella-static/index.htmlMajestic Millionhttps://majestic.com/reports/majestic-millionTranco-List.euhttps:…

这回稳了,蓝桥杯才是yyds!

为了提高自己的编程能力&#xff0c;很多人会选择参加比赛。而这些比赛中&#xff0c;连续三年入选“全国普通高校学科竞赛排行榜”的蓝桥杯大赛&#xff0c;可以综合测评加分&#xff0c;优先奖学金评定、升学考研加分&#xff0c;yyds !! 蓝桥杯大赛报名截止至12月16日&…

Win 11 安装pycolmap

1.vcpkg安装 1.1 下载vcpkg源码 >> git clone gitgithub.com:microsoft/vcpkg.git1.2 编译生成vcpkg工具 >> .\vcpkg\bootstrap-vcpkg.bat这样在vcpkg文件夹下就会生成vcpkg.exe文件 2.colmap安装 2.1 命令安装colmap的gpu版本 >> .\vcpkg install col…

矩阵 行列式的计算

行列式要求 要计算行列式&#xff0c;那么这个矩阵一定是一个方阵 行列式性质 行列式转置后值不变互换行列式中两行&#xff0c;值变为相反数行列式中两行成比例&#xff0c;行列式为0行列式中一行所有元素乘以一个数后加到另一行&#xff0c;行列式值不变 行列式的计算有很…

【编译原理】第二章部分课后题答案

《编译原理&#xff08;第三版&#xff09;》陈意云著 第 二 章 课 后 习 题 T 2.3 叙述由下列正规式描述的语言 0(0∣1)∗0\space\space0\space\space(\space\space 0\space\space |\space\space 1\space\space)^{\space*\space\space}00 ( 0 ∣ 1 ) ∗ 0 正规式规定开…

Java搭建宝塔部署实战毕设项目springboot销售培训考评系统源码

大家好啊&#xff0c;我是测评君&#xff0c;欢迎来到web测评。 本期给大家带来一套Java开发的毕业设计项目springboot销售培训考评系统源码。 技术架构 技术框架&#xff1a;jQuery MySQL5.7 mybatis shiro Layui HTML CSS JS jpa运行环境&#xff1a;jdk8 IntelliJ…

【Linux】四、Linux 进程概念(三)|进程优先级|环境变量

目录 七、进程优先级 7.1 基本概念 7.1.1 什么是优先级 7.1.2 为什么存在优先级 7.1.3 Linux 优先级特点 7.2 查看系统进程 7.3 PRI 和 IN 7.4 查看进程优先级和更改进程优先级 7.5 其它概念 7.6 进程切换 八、环境变量 8.1 环境变量基本概念 8.2 常见环境变量 8…

windows下node.js通过N-API调用c++函数

环境准备 vscode安装&#xff08;以下均在vscode中操作&#xff09;node.js安装&#xff0c;版本不要太老c工具链安装&#xff0c;安装Visual Studio2019社区版即可&#xff0c;或者执行 npm install --global windows-build-tools&#xff08;这个我没试过&#xff0c;window…

ARM SDRAM

前言 涉及到的文档&#xff1a; S5PV210_UM_REV1.1 x210cv3.pdf K4T1G164QE.pdf 一、SDRAM 引入 1、简介 SDRAM&#xff1a;Syncronized Dynamic Ramdam Access Memory&#xff0c;同步动态随机存储器; DDR&#xff1a;DDR 就是 DDR SDRAM&#xff0c;是 SDRAM 的升级版。…

[论文分享] DnD: A Cross-Architecture Deep Neural Network Decompiler

DnD: A Cross-Architecture Deep Neural Network Decompiler [USENIX 2022] Ruoyu Wu Purdue University Taegyu Kim The Pennsylvania State University Dave (Jing) Tian Purdue University Antonio Bianchi Purdue University Dongyan Xu Purdue University 深度神经网络(…