代码笔记_AE_HMEAE

一 数据预处理

HMEAE中数据预处理很有特色,特别是论元数据预处理。

样本数据

1.HMEAE中样本和DMCNN中一样,根据候选触发词的思路来划分样本,也就是对于一个句子,将每个词逐个视为候选触发词,每次对应一个样本。
2.另一点比较重要的是,每个样本中记录中句子中的所有命名实体,并且为实体加上论元标签。如果,当前样本中的候选触发词是真正的触发词,那么实体的论元标签就是各实体在该触发词下的论元角色。如果,样本中候选触发词不是触发词,那么实体的论元标签都为None3.上述的原始数据可以直接作为ED的输入,AE的输入要进一步处理。先用ED筛选触发词标签正确的样本,然后依次将样本中的实体作为候选论元,因此衍生出多个样本。

这里有两个问题:
1.一个词在多个触发词中充当不同的角色;
2.一个词在一个触发词中充当多个角色;
在这两种情况在ACE2005中有标注吗?
第一个情况,按照文章的说法是能够覆盖的,样本中还没专门去找看看,如果ACE2005本身标注了,那么不成问题。
第二个情况,文章是没有处理的。

利用ED预测结果筛选AE数据集

	# 训练ED模型;并生成AE的dev、test数据集
    def train_trigger(self):
		train, dev, test = self.t_train, self.t_dev, self.t_test
		...
		with tf.Session() as sess:
    		... 训练并保存得到的ED模型
    		# 生成AE的数据集:a_data_process = (train,dev,test)
            # train直接来源于原始数据
            # dev、test是基于ED模型,将ED预测的事件类型加入到数据集中,构成新的dev、test
            # dev、test比train多了预测事件类型这一列
            a_data_process = self.predict_trigger(sess)
        return a_data_process

	# 加载ED模型,预测dev、test中的事件类型
    def predict_trigger(self, sess):
        print('--Predict Trigger For Argument Stage--')
        # 注意:这里的输入不是t_data,而是a_data了
        # 从更前面的数据预处理可以看到,这里train、dev、test的产生方式是不一样的
        # train是根据gold标签过滤了事件类型为None的样本;dev、test并没有过滤,产生方式和ED部分完全一样
        # dev、test是在这里根据ED预测标签来过滤事件类型为None的样本

        # 那么有个疑问,为啥train使用gold过滤,而dev、test使用ED预测结果过滤?
        #   个人理解:这完全是为了和之前的DMCNN具有可比性,或者说与ED/AE联合模型具有可比性,不过话说回来,DMCNN是联合模型吗?AE部分是用ED预测值作为trigger标签的吗?
        #   如果是的话,就说得通;还是说是流水线模型,训练的时候用的是gold值,那也不会dev、test用ED预测值吧,搞不懂,再看看吧
        #   不过也说明了,可比性这玩意很扯啊,这里作者实现了DMCNN的ED部分,却没有直接拿触发词标签真实值单独测一下DMCNN的AE部分,然后比较
        #   因为DMCNN没有官方开源的代码,你自己实现的可能说服力不够吧
        train, dev, test = self.a_train, self.a_dev, self.a_test
        # tf 加载模型
        saver = tf.train.Saver()
        saver.restore(sess, "saved_models/trigger.ckpt")
        # dev、test中的事件类型
        dev_pred_event_types = []
        test_pred_event_types = []

        # dev_pred_event_types、test_pred_event_types 记录ED预测的事件类型,注意这里面包括None的
        for batch in get_batch(dev, constant.t_batch_size, False):
            pred_label = list(sess.run(self.pred_label, feed_dict=get_argument_feeddict(self, batch, False, 'trigger')))
            dev_pred_event_types.extend(pred_label)
        for batch in get_batch(test, constant.t_batch_size, False):
            pred_label = list(sess.run(self.pred_label, feed_dict=get_argument_feeddict(self, batch, False, 'trigger')))
            test_pred_event_types.extend(pred_label)
        return self.process_data_for_argument(np.array(dev_pred_event_types, np.int32),
                                              np.array(test_pred_event_types, np.int32))

	# 使用ED预测结果过滤掉dev、test中事件类型为None的样本,得到新的dev、test
    def process_data_for_argument(self, dev_pred_event_types, test_pred_event_types):
        print('--Preprocess Data For Argument Stage--')
        # 这里train、dev、test还是原始数据
        train, dev, test = list(self.a_train), list(self.a_dev), list(self.a_test)

        # 下面的两个操作导致,dev、test比train多了一列;ED预测的事件类型
        # 注意啦:这里往dev中多加了一列dev_pred_event_types;这个表示ED预测的事件类型(还是很别扭,预测的不是触发词对应的事件类型,而是事件类型;因为逐个词作为候选触发词);
        dev = list(dev)
        dev.append(dev_pred_event_types)
        dev = tuple(dev)
        # 注意啦:同上,这里往test中多加了一列test_pred_event_types;
        test = list(test)
        test.append(test_pred_event_types)
        test = tuple(test)

        dev_slices = []
        # 这里删除掉预测事件类型为None的样本
        for idx, event_type in enumerate(list(dev_pred_event_types)):
            if event_type != 0:
                dev_slices.append(idx)

        test_slices = []
        # 这里删除掉预测事件类型为None的样本
        for idx, event_type in enumerate(list(test_pred_event_types)):
            if event_type != 0:
                test_slices.append(idx)

        # 这个意思是说,只把ED预测的事件类型不为None的样本筛选出来,作为新的dev、test
        # 有个问题啊,gold不为None但是ED预测为None的样本也被过滤了,有影响吗?
        # 没有影响,因为这里筛选只是减少了dev、test样本的数量,也就是减少了数据集的数量,
        # 而不是改变AE模型预测的结果,所以没有不影响
        dev = [np.take(d, dev_slices, axis=0) for d in dev]
        test = [np.take(d, test_slices, axis=0) for d in test]
        return train, dev, test

返回AE数据集

# tf中这里才是模型的输入,将batch中数据和计算图中变量名对应上
def get_argument_feeddict(model,batch,is_train=True,stage='trigger'):
    if stage=='trigger':
        sents,event_types,roles,maskl,maskm,maskr,\
        trigger_lexical,argument_lexical,trigger_maskl,trigger_maskr,trigger_posis,argument_posis = batch
        return get_trigger_feeddict(model,(trigger_posis,sents,trigger_maskl,trigger_maskr,event_types,trigger_lexical),False)
    elif stage=="argument":
        # 注意看:预测时比训练时多了一个pred_event_types,也就是说batch不一样了;
        if is_train:
            sents,event_types,roles,maskl,maskm,maskr,\
            trigger_lexical,argument_lexical,trigger_maskl,trigger_maskr,trigger_posis,argument_posis = batch
            # 对应模型中的变量名:
            # sents、trigger_posis、argument_posis、maskls、maskms、maskrs、trigger_lexical、argument_lexical、
            # _labels、is_train、event_types
            # 需要注意的是:数据中的roles在模型中对应_labels
            return {model.sents:sents,model.trigger_posis:trigger_posis,model.argument_posis:argument_posis,
                    model.maskls:maskl,model.maskms:maskm,model.maskrs:maskr,
                    model.trigger_lexical:trigger_lexical,model.argument_lexical:argument_lexical,
                    model._labels:roles,model.is_train:is_train,model.event_types:event_types}
        else:
            sents,event_types,roles,maskl,maskm,maskr,\
            trigger_lexical,argument_lexical,trigger_maskl,trigger_maskr,trigger_posis,argument_posis,pred_event_types = batch
            # 这个也是因垂丝汀啊:把pred_event_types单独提出来了
            return pred_event_types,{model.sents:sents,model.trigger_posis:trigger_posis,model.argument_posis:argument_posis,
                    model.maskls:maskl,model.maskms:maskm,model.maskrs:maskr,
                    model.trigger_lexical:trigger_lexical,model.argument_lexical:argument_lexical,
                    model._labels:roles,model.is_train:is_train,model.event_types:pred_event_types}
    else:
        raise ValueError("stage could only be trigger or argument")

X 其他

注意:这个代码里面没有使用BIO标签,DMCNN里面用了吗?论文没看到说明,代码没开源;

名词作为触发词的例子:

'CNN_CF_20030303.1900.00'
['He', 'lost', 'an', 'election', 'to', 'a', 'dead', 'man']

从这个代码里面反思:
1.word2idx什么时候执行?
可以在产生dataset时、从dataloader中获取batch时、forward输入时;放在这些地方都是可以的,到底放在哪里更好?这份代码放在了,dataloader中;一般来说,对数据的预处理也确实也是放在dataloader中,比如pad;JMEE放在dataset中了;之所以放在dataloader之中或者之前,是为了方便后面pad。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值