2021-05-27 xf_event_extraction-trigger训练部分

train_features = convert_examples_to_features(opt.task_type, train_examples, opt.bert_dir,
                                                  opt.max_seq_len, **feature_para)

数据预处理后变这样:
输入:单个样本如下
    # token_ids= [101, 1333, 3403,.....,1469, 3856, 102]
    # attention_masks = [1, 1, 1,...,1, 1]  有字的为1
    # token_type_ids = [0, 0,.......,0, 0]   对单个句子而言全是0  不存在奇偶句
      labels = [[0, 0], [0, 0],[1, 0], [0, 1],..,[0, 0], [0, 0]]  ,其中[1, 0], [0, 1]是触发词位置   分起始和结束位置
    #[0, 0, ....1, 1, ....0, 0] 其中1,1是distant_triggers位置,不分起始和结束位置。

这5个作为输入。

数据预处理:

processor.get_train_examples(train_aux_raw_examples):

set_type = train/dev (训练时train,评估模型是dev)
examples.append(TriggerExample(set_type=set_type,
                                           text=text,
                                           label=tmp_triggers,
                                           distant_triggers=_ex['distant_triggers']))

callback_info.append((text, tmp_triggers, _ex['distant_triggers']))

            # (callback_info和examples 的区别为 一个是元组 一个是 对象)
            # [('原标题:2019年反腐败“成绩单”亮眼●从数据上看,2019年的反腐败成绩单引人注目,反映了当前反腐败力度仍然没有放松、'
            #   '反腐败工作仍然按照既定目标推进、高压反腐态势仍然保持,由此查处的中管干部、省管干部这些“关键少数”干部数量仍然保持高位'
            #   '并呈现增长态势●2019年反腐败主要呈现三个方面的特点:一是精准反腐;二是强化标本兼治;三是深化基层反腐败●'
            #   '中央针对全面从严治党和党风廉政建设领域,出台了一系列具有代表性的党内法规制度,为整个监察体制改革提供了制度保障,'
            #   '同时着力建立健全一个具有中国特色的监察法律体系,推动制度反腐、法治防腐制图/李晓军2019年12月26日14时30分,'
            #   '中央纪委国家监委网站发布了年度最新一条执纪审查消息,“呼和浩特职业学院原党委副书记、院长李怀柱接受纪律审查和监察调查”',
            #  [('发布', 298)], ['接受', '发布', '推进', '提供', '建立', '推动', '出台', '建设', '调查', '改革'])]

训练时只返回训练集的examples 列表
评估模型时 返回验证集的examples 和 callback_info

数据转化为输入特征:

tokens = fine_grade_tokenize(raw_text, tokenizer)
# tokens = ['原', '标', '题', ':', '2', '0',........'查', '”']

tokenizer = BertTokenizer.from_pretrained(bert_dir)

for i, example in enumerate(tqdm(examples, desc=f'convert examples')):

    feature = convert_trigger_example(
                    ex_idx=i,
                    example=example,
                    max_seq_len=max_seq_len,
                    tokenizer=tokenizer,
                )
    
    encode_dict = tokenizer.encode_plus(text=tokens,
                                        max_length=max_seq_len,
                                        pad_to_max_length=True,
                                        is_pretokenized=True,
                                        return_token_type_ids=True,
                                        return_attention_mask=True)

    token_ids = encode_dict['input_ids']
    attention_masks = encode_dict['attention_mask']
    token_type_ids = encode_dict['token_type_ids']
    # token_ids= [101, 1333, 3403,.....,1469, 3856, 102]
    # attention_masks = [1, 1, 1,...,1, 1]  有字的为1
    # token_type_ids = [0, 0,.......,0, 0]   对单个句子而言全是0  不存在奇偶句

    # labels = [[0, 0], [0, 0],[1, 0], [0, 1],..,[0, 0], [0, 0]]  ,其中[1, 0], [0, 1]是触发词起始结束位置  
    # [0, 0, ....1, 1, ....0, 0] 其中1,1是distant_triggers位置 训练时该项设置False
    
    feature = TriggerFeature(token_ids=token_ids,
                             attention_masks=attention_masks,
                             token_type_ids=token_type_ids,
                             distant_trigger_label=distant_trigger_label,
                             labels=labels)
    class BaseFeature:
        def __init__(self,
                     token_ids,
                     attention_masks,
                     token_type_ids,
                     labels=None):
            self.token_ids = token_ids
            self.attention_masks = attention_masks
            self.token_type_ids = token_type_ids
            self.labels = labels


    class TriggerFeature(BaseFeature):
        def __init__(self,
                     token_ids,
                     attention_masks,
                     token_type_ids,
                     distant_trigger_label=None,
                     labels=None):
            super(TriggerFeature, self).__init__(token_ids=token_ids,
                                                 attention_masks=attention_masks,
                                                 token_type_ids=token_type_ids,
                                                 labels=labels)
            self.distant_trigger_label = distant_trigger_label

    features.append(feature)  # 每个样例变成一个对象,然后添加到列表
其中 self.token_ids = token_ids= [101, 1333, 3403,.....,1469, 3856, 102]
     self.attention_masks =  [1, 1, 1,...,1, 1]  有字的为1
     self.token_type_ids = [0, 0,.......,0, 0]   对单个句子而言全是0  不存在奇偶句
     self.labels = [[0, 0], [0, 0],[1, 0], [0, 1],..,[0, 0], [0, 0]]  ,其中[1, 0], [0, 1]是触发词起始结束位置
     self.distant_trigger_label = [0, 0, ....1, 1, ....0, 0] 其中1,1是distant_triggers位置 训练时该项设置False

转化成自动迭代的有bach_size格式:

train_dataset = build_dataset(opt.task_type, train_features, 'train', **dataset_para)
# opt.task_type = trigger
class TriggerDataset(BaseDataset):
    def __init__(self,
                 features,
                 mode,
                 use_distant_trigger=False):
        super(TriggerDataset, self).__init__(features, mode)

        self.distant_trigger = None

        if use_distant_trigger:
            self.distant_trigger = [torch.tensor(example.distant_trigger_label).long()
                                    for example in features]

    def __getitem__(self, index):
        data = {'token_ids': self.token_ids[index],
                'attention_masks': self.attention_masks[index],
                'token_type_ids': self.token_type_ids[index]}

        if self.distant_trigger is not None:
            data['distant_trigger'] = self.distant_trigger[index]

        if self.labels is not None:
            data['labels'] = self.labels[index]

        return data

train_loader = DataLoader(dataset=train_dataset,
                          batch_size=opt.train_batch_size,
                          sampler=train_sampler,
                          num_workers=8)

for epoch in range(opt.train_epochs):

   for step, batch_data in enumerate(train_loader):

        model.train()

        for key in batch_data.keys():
        #key = token_ids / attention_masks / tokem_yype_ids / labels
        batch_data[key] = batch_data[key].to(device)
        #len(batch_data)=4  分别是token_ids / attention_masks / tokem_yype_ids / labels的值      batch_data[token_ids].shape = [4,320] bsz和句子长度
        loss = model(**batch_data)[0]       #[0]为loss [1]为预测的logits

模型构建

model = build_model(opt.task_type, opt.bert_dir, **model_para)

self.bert_module = BertModel.from_pretrained(bert_dir)

bert_outputs = self.bert_module(
            input_ids=token_ids,
            attention_mask=attention_masks,
            token_type_ids=token_type_ids
        )

seq_out = bert_outputs[0]   #seq_out.shape = bert_outputs[0].shape = (4, 320, 768)
                                                   # bert_outputs[1].shape = (4, 768)

self.mid_linear = nn.Sequential(
                  nn.Linear(out_dims, mid_linear_dims),
                  nn.ReLU(),
                  nn.Dropout(dropout_prob)
                  )
        # Sequential(
        # (0): Linear(in_features=768, out_features=128, bias=True)
        # (1): ReLU()
        # (2): Dropout(p=0.1, inplace=False)
        # )

self.classifier = nn.Linear(mid_linear_dims, 2)

self.criterion = nn.BCELoss()

seq_out = self.mid_linear(seq_out)  # [4, 320, 128]

logits = self.activation(self.classifier(seq_out)) # [4, 320, 2]

if labels is not None: #True
      loss = self.criterion(logits, labels.float())  #labels.shape = [4, 320, 2]  loss = 0.6610
      out = (loss,) + out #相当于列表的添加操作
      #out 为元组 (loss的值,out的输出)
      return out

训练完成到指定步数存储模型,并评估模型:

验证集 也转换为输入特征,最后 pred_logits.shape = (369, 320, 2)  #369是全部验证集的总量

设置阈值kwargs = {'start_threshold': 0.5, 'end_threshold': 0.5}
    start_ids = np.argwhere(logits[:, 0] > start_threshold)[:, 0]    #[:, 0]之前如果是 [[1]  之后变为 [1 3],作用就是变成一行
                                                                                      #[3]]
    end_ids = np.argwhere(logits[:, 1] > end_threshold)[:, 0]

    #   _start 和 _end 自由组合,选出小于 长度为3的组合 放入候选
    for _start in start_ids:
        for _end in end_ids:
            # 限定 trigger 长度不能超过 3
            if _end >= _start and _end - _start <= 2:
                # (start, end, start_logits + end_logits)
                candidate_entities.append((raw_text[_start: _end + 1], _start, logits[_start][0] + logits[_end][1]))
                break

情况1:_start 和 _end 自由组合,选出小于 长度为3的组合 放入候选,然后选出一个最大的(起始logits和结束logits的和)。

以下是没有大于阈值或者不满足自由组合的条件即candidate_entities列表为空

情况2 if not len(candidate_entities):
     没有的话 就选出 distant_triggers中的标签,每个标签有个起始logits和结束logits的和,然后选出一个最大的(起始logits和结束logits的和)。

情况3:连distant_triggers都没有的话,选取最大的(起始logits和结束logits的和)作为 trigger。

计算F1

gt, predict = [('投资', 31)],[('投资', 31)]  ------------->  if '投资' == '投资'  and   31 == 31 ------------------->预测正确。然后计算P和R 然后计算F1

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值