信息抽取(一)机器阅读理解——样本数据处理与Baseline模型搭建训练(2020语言与智能技术竞赛)

本文是信息抽取系列的第一篇,关注机器阅读理解任务。通过介绍数据处理、构建模型和训练过程,展示了一个简单的Baseline模型。在数据处理上,作者强调了answer_start的重要性,并分享了数据提取和处理的思路。模型训练采用了K折交叉验证,结果显示模型能够准确预测答案的位置。后续计划复现关系抽取和事件抽取任务。
摘要由CSDN通过智能技术生成

机器阅读理解——样本数据处理与Baseline模型搭建训练


前言

最近看到今年早些时候百度的“2020语言与智能技术竞赛”比赛,里面有五个赛道,三个赛道与信息抽取有关,分别是机器阅读理解、关系抽取、事件抽取。最近正好对信息抽取任务比较感兴趣,所以拿来复现一下baseline模型,同时参考参考大佬们的想法,学习下思想和技巧。

参考比赛:Tweet Sentiment Extraction2020语言与智能技术竞赛-机器阅读理解,这个两个赛题都涉及到了信息抽取

Tweet Sentiment Extraction:通过给定的tweet,以及其情感倾向,从该条tweet中抽取可以代表其情感倾向的词句。

2020语言与智能技术竞赛-机器阅读理解:给定背景内容context,根据所给问题,从context中抽取对应的答案。

其实Tweet Sentiment Extraction也可以看作阅读理解问题,只是把tweet和emotion作为context,而问题固定(抽取情感语句)。

这篇是信息抽取系列的第一篇:即机器阅读理解,比起其他两个信息抽取任务来说,可以算是小打小闹了,baseline模型也比较简单,通过两个softmax,找到答案的start和end即可。

但在数据集构建时真的不知道出了多少bug,最后自己总结一个模版,可以用在中文和英文并且对标注的数据有很大的噪声容忍度的SQuAD任务的数据集生成方法。


样本数据处理

数据样例:数据为json格式,每条样本包含context、question、id、answers:text、answer_start(答案的起始位置)。
注意这个answer_start很重要,后面有妙用,如果当文中出现重复的答案片段时,要保证你的y值和answer_start保持一致,而且answer_start可以用来处理过长(>512)的context,把每一个样本数据都利用起来。

'''{
    "data": [
        {
            "title": "", 
            "paragraphs": [
                {
                    "context": "第35集雪见缓缓张开眼睛,景天又惊又喜之际,长卿和紫萱的仙船驶至,见众人无恙,也十分高兴。\
                    众人登船,用尽合力把自身的真气和水分输给她。\
                    雪见终于醒过来了,但却一脸木然,全无反应。众人向常胤求助,却发现人世界竟没有雪见的身世纪录。\
                    长卿询问清微的身世,清微语带双关说一切上了天界便有答案。长卿驾驶仙船,众人决定立马动身,往天界而去。\
                    众人来到一荒山,长卿指出,魔界和天界相连。由魔界进入通过神魔之井,便可登天。众人至魔界入口,仿若一黑色的蝙蝠洞,但始终无法进入。\
                    后来花楹发现只要有翅膀便能飞入。于是景天等人打下许多乌鸦,模仿重楼的翅膀,制作数对翅膀状巨物。刚佩戴在身,便被吸入洞口。众人摔落在地,抬头发现魔界守卫。\
                    景天和众魔套交情,自称和魔尊重楼相熟,众魔不理,打了起来。", 
                    "qas": [
                        {
                            "question": "仙剑奇侠传3第几集上天界", 
                            "id": "0a25cb4bc1ab6f474c699884e04601e4", 
                            "answers": [
                                {
                                    "text": "第35集", 
                                    "answer_start": 0
                                }
                            ]
                        }
                    ]
                },
'''

数据提取,这里就不多介绍怎么把样本以结构的形式取出,我的方法比较笨。

def data_load(path):
    with open(path) as json_file:
        data = json.load(json_file)
    context = [x['context'] for x in data['data'][0]['paragraphs']]
    question = [x['qas'][0]['question'] for x in data['data'][0]['paragraphs']]
    answers_text = [x['qas'][0]['answers'][0]['text'] for x in data['data'][0]['paragraphs']]
    answer_start = [x['qas'][0]['answers'][0]['answer_start'] for x in data['data'][0]['paragraphs']]
    return context,question,answers_text,answer_start

训练样本处理:前方高能
主要思路:找到answer与context重合的区域,对context进行编码,再反解码后,如果反解码出来的文字在原生context中的位置处于答案重合区域,则该文字的token视为答案的一部分,找到连续答案token取第一个为start_index,最后一个为end_index。

def train_data_proceed(tokenizer,context,question,answers_text,answer_start,MAX_LEN==512):
    ct = len(context)
    input_ids = np.zeros((ct,MAX_LEN),dtype='int32')
    attention_mask = np.zeros((ct,MAX_LEN),dtype='int32')
    start_tokens = np.zeros((ct,MAX_LEN),dtype='int32')
    end_tokens = np.zeros((ct,MAX_LEN),dtype='int32')
    
    '''
    这里我们不再用transfomers自带的tokenizer直接编码文本
    而是自己定义input_ids和attention_mask,是为了方便计算start_tokens和end_tokens
    '''
    
    for k in range(ct):
        context_k = context[k]
        question_k = question[k]
        answers_text_k = answers_text[k]
        answer_start_k = answer_start[k]
		'''
		坑1:在处理context的时候发现tokenizer对文本中的' '空格是不编码的,因此会导致反解码时,会省略空格,使得context 与 context_encode_decode顺序错乱。
		因此这里repalce掉答案出现之间的空格,相应的answer_start也向前移动x,x为取出空格的数量。
		'''
        answer_start_k = answer_start_k - len(re.findall(' ',context_k[:answer_start_k]))
        context_k = context_k.replace(' ','')
        
        '''
        定义最后 input_ids 的形式
        [cls] question [sep] context [sep] [pad] [pad] ......
        '''
        
        if len(question_k) + 3 + len(context_k)>= MAX_LEN:
            '''
            如果形成的input_ids长度大于MAX_LEN,则考虑对context进行截取,定义截取context中答案前后 长为X 字符的片段
            则有公式:answer_start_k+len(answers_text_k)+x - (answer_start_k-x)+3+len(question_k) <= MAX_LEN
            解得:2x = MAX_LEN-len(answers_text_k) - 3 -len(question_k)
            '''
            x = (MAX_LEN-len(answers_text_k) - 3 -len(question_k))
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值