精华内容
下载资源
问答
  • OpenNRE We have a DEMO website (http://opennre.thunlp.ai/). Try it out! OpenNRE is an open-source and extensible toolkit that provides a unified framework to implement relation extraction models. ...
  • import opennre 出错

    2021-01-07 14:48:31
    <div><p>安装后import opennre 出错:TypeError: expected str, bytes or os.PathLike object, not NoneType,请问有遇到同样问题的吗?</p><p>该提问来源于开源项目:thunlp/OpenNRE</p></...
  • OpenNRE源码结构解读

    2021-02-23 22:35:37
    OpenNRE源码结构解读 THUNLP OpenNRE开源模型代码解读,以BagRE为例。 structure 层次:framework(BagRE) - model(BagAttention) - encoder(PCNN) framework(BagRE) dataLoader = BagRELoader datasest = ...

    OpenNRE源码结构解读

    THUNLP OpenNRE开源模型代码解读,以BagRE为例。

    structure

    层次:framework(BagRE) - model(BagAttention) - encoder(PCNN)

    • framework(BagRE)
      • dataLoader = BagRELoader

        • datasest = BagREDataset
          • tokenizer = model.sentence_encoder.tokenize(传入的model的成员的函数对象)
          • getitem函数为
            • 见下
      • model = BagAttention(传入的参数)

        • sentence_encoder = PCNNEncoder(在实例化时传入的参数)
          • 继承自父类BaseEncoder,其中包含
            • tokenizer = WordTokenizer(vocab=self.token2id)
              • token2id (dictionary of token->idx mapping)
            • word & pos1,2 embeddings,
          • tokenize函数为
            • Sentence -> Token: 利用BaseEncoder的tokenizer.tokenize进行分词(得到切分好的List of wordpieces & pos)
            • Token -> index: 利用tokenizer.convert_tokens_to_ids得到indexed_tokens(通过utils.convert_by_vocab
            • Position -> index | Mask | Padding: pos1, pos2, mask
            • return indexed_tokens, pos1, pos2, mask
          • forward函数为
            • arg:按batch的上述返回值,尺寸为(B, L),L为sentence length
            • ret:按batch输出向量表示,尺寸为(B, EMBED)
      • num classes, id2rel mapping,用于模型内部的卷积、线性层

      • forward函数:

        • 先通过view展平为nsum(一个bag有n个sentence,批量处理B个bag对应nsum个sentence,每个bag中的sentence利用scope确定)
        • 然后encode为H=EMBED(隐藏层尺寸即词嵌入dim)
        • 再经过attention得到score,经过softmax得到logits
        • def forward(self, label, scope, token, pos1, pos2, mask=None, train=True, bag_size=0):
              """
              Args:
                  label: (B), label of the bag
                  scope: (B), scope for each bag
                  token: (nsum, L), index of tokens
                  pos1: (nsum, L), relative position to head entity
                  pos2: (nsum, L), relative position to tail entity
                  mask: (nsum, L), used for piece-wise CNN
              Return:
                  logits, (B, N)
              """
              
              # 1. get representation, size (nsum, H)
              if bag_size > 0: # bag-level
                  token = token.view(-1, token.size(-1))
                  # same for pos1, pos2, mask if not None
              else: # sentence-level
                  begin, end = scope[0][0], scope[-1][1]
                  token = token[:, begin:end, :].view(-1, token.size(-1))
                  # same for pos1, pos2, mask if not None
                  scope = torch.sub(scope, torch.zeros_like(scope).fill_(begin)) # subtract begin to get relative index
              rep = self.sentence_encoder(token, pos1, pos2, mask)
              
              # 2. get bag representation via attention, size (B, H)
              if train:
                  if bag_size > 0: # bag-level
                      # get basic parameter B
                      batch_size = label.size(0)
                      query = label.unsqueeze(1) # (B, 1)
                      
                      # use attention matrix in self.fc.weight.data (?)
                      att_mat = self.fc.weight.data[query] # (B, 1, H)
                      
                      # restore flattened representation of size(nsum, H)
                      rep = rep.view(batch_size, bag_size, -1) # (B, bag, H)
                      att_score = (rep * att_mat).sum(-1) # (B, bag)
                      softmax_att_score = self.softmax(att_score) # (B, bag)
                      bag_rep = (softmax_att_score.unsqueeze(-1) * rep).sum(1) # (B, bag, 1) * (B, bag, H) -> (B, bag, H) -> (B, H)
                  else: # sentence-level
                      
                  bag_rep = self.drop(bag_rep)
                  bag_logits = self.fc(bag_rep) # (B, N)
          
          
      • train_model

      • eval_model:在test_loader (ent_pair_as_bag=True)上测试

        • 计算所有非NA的pred_result
        • 传入dataset.eval,计算P@100, 200, 300和F1等

    BagREDataset

    notation:

    """
        B:batch size
        n:size of bag (sentence num)
        L:sentence length
        nsum:total length of all flattened n sentences in bag
        	(bag中n个sentences展平成一行的长度)
        H:hidden size
    """
    

    Dataset: bag-level,一个bag包含相同name的许多instances,其中name=(h, t, r)或(h, t);

    • bag scope:key=name2id[name],value=[包含了所有这个name的句子的idx](list);
    • bag name:一般是relation fact的三元组,如果开启了entpair_as_bag就忽略relation变成二元组;
      • 对于NA关系,self.facts中将这个三元组置0,其余置1
    • weight:对于每种relation(以rel id为编号),记录为1 / (facts总数^0.05)
    • __getitem__
      • 在bag scope中根据index(nameid)选择一个bag
      • 根据bag[0](list的第0号元素)的relation得到rel id
      • 遍历bag,对于每个包含了这个name的句子的sent_id
        • item = self.data[sent_id],获取句子完整信息
        • seq = list(self.tokenizer(item)),词嵌入,得到的List=[indexed_tokens, pos1, pos2, mask]
        • 然后把按sentence得到的seq列表append到seqs对应位置处
      • 得到seqs=[[token list], [pos1 list], [pos2 list], [mask list]],然后再torch.cat得到i=0~2的seqs[i]尺寸为(n, L),n个句子,L为句子长度
      • return [rel, self.bag_name[index], len(bag)] + seqs,即[label, bag_name, scope, token, pos1, pos2, mask]

    BagAttention

    TODO

    BagRE

    • Scope:尺寸为bag大小B(instance数目),如

    • scope=tensor([[  0,   1],
            [  1,   2],
            [  2,   3],
            [  3,   4],
            ...,
            [255, 258],
            [258, 260]])
      
      	torch.Size([1, 260]) # (1, nsum)
      
    • Token,pos1&2,mask:输入尺寸与参数bag size(指定bag大小,如果为0则用原来数据集划分的bag)有关

    • # if bag_size == 0
      token, pos1, pos2, mask => torch.Size([1, 260, 120]) # (1, nsum, L)
      
      # expected
      token, pos1, pos2, mask => torch.Size([1, 260, 120]) # (nsum, L)
      rep=torch.Size([260, 690]) # (nsum, H)
      
    展开全文
  • thunlp的OpenNRE的使用

    千次阅读 2019-11-28 20:55:20
    发表OpenNRE的论文,论文详细说明了OpenNRE的各个组件。 OpenNRE的github的地址。 清华整理的做关系抽取必读的文章的地址。 OpenNRE实现了基于sentence-level,bag-level和few-shot的relation extraction(关系抽取...

    发表OpenNRE的论文,论文详细说明了OpenNRE的各个组件。
    OpenNRE的github的地址
    清华整理的做关系抽取必读的文章的地址

    OpenNRE实现了基于sentence-level,bag-level和few-shot的relation extraction(关系抽取)。bag-level的关系抽取也就是基于远程监督的关系抽取。

    OpenNRE的结构

    OpenNRE主要包括Tokenization,Module,Encoder,Model,Framework这5部分组成。

    Tokenization

    这个组件的任务是将输入文本分割成word-level和subword-level的两种token流。如果想要新建一个新的类型的token流可以通过继承BasicTokenizer类来实现。

    Module

    这个组件主要包括用于模型实现的各种功能神经模块组成,如基本的网络层、一些池操作和激活功能。

    Encoder

    这个组件主要将编码器应用于将文本编码到其相应的embedding中以提供语义特性。作者基于前面的Tokenization和Module组件实现了BaseEncoder类,这个类可以实现token的embedding,也可以通过继承这个类来实现自己的encoder。同时作者也实现了一些常用的编码器结构,比如LSTM,Bert等。

    Model

    这个组件作者实现了一些经典的关系抽取模型,比如基于CNN的关系抽取模型等,还实现了一些其他的用于提升模型性能的算法,比如注意力机制,对抗训练,强化学习等。

    Framework

    这个组件主要负责集成其他四个组件,支持各种功能(包括数据处理、模型训练、模型优化、模型评估)。并实现了基于sentence-level,bag-level和few-shot的关系抽取。
    在这里插入图片描述

    示例

    在这里插入图片描述

    展开全文
  • OpenNRE(https://github.com/thunlp/OpenNRE.git)是清华大学自然语言处理实验室推出的一款开源的神经网络关系抽取工具包,包括了多款常用的关系抽取模型,发布仅一年即在 Github 上获得了 1700+ 星标。现在这款工具...

    4973b2de8c84fb3fc3795a5ef3a98de2.gif

    OpenNRE(https://github.com/thunlp/OpenNRE.git)是清华大学自然语言处理实验室推出的一款开源的神经网络关系抽取工具包,包括了多款常用的关系抽取模型,发布仅一年即在 Github 上获得了 1700+ 星标。

    f34469b2dc6bd431e6dce86e910cdb4a.png

    现在这款工具包已经悄悄更新到了 2.0 版本!在原版 TensorFlow 实现的基础上,不仅采用了现在大热的 PyTorch 作为基础,设计了更加模块化的框架,还囊括了句子级别关系抽取、远监督关系抽取和少次学习关系抽取等丰富设定,可以说是加量不加价,值得你拥有!

    0e315ad5b9638fb6be4a01d7eae2a893.png

     OpenNRE框架图

    同时,该工作也以 DEMO Paper 的形式发表在了 EMNLP 2019 上,这里是 paper 的地址: 

    OpenNRE: An Open and Extensible Toolkit for Neural Relation Extraction https://arxiv.org/abs/1909.13078 

    作者在介绍文档中还写道,相比于原版主要面对关系抽取研究者的设定,新版的 OpenNRE 受众更加广泛:

    • 对于初学者:OpenNRE 提供了详尽的介绍文档,可以快速帮助入门

    • 对于开发者:提供了简洁易用的 API 和若干预训练模型,可方便调用

    • 对于研究者:模块化设计、多种任务设定、state-of-the-art 模型,可以帮助研究者更快更高效的进行探索

    • 想要在 NLP 课上交一份满意大作业的同学:这个项目里的模型绝对能让你的教授眼前一亮

    e923bc85efd3fe2ce836911c409d3781.png

    什么是关系抽取

    关系抽取是自然语言处理当中的一项重要任务,致力于从文本中抽取出实体之间的关系。比如从句子“达芬奇绘制了蒙娜丽莎”中,我们可以抽取出(达芬奇,画家,蒙娜丽莎)这样一个关系三元组。

    关系抽取技术是自动构建知识图谱的重要一环。知识图谱是由真实世界中的实体和实体间复杂关系构成的结构化表示,是帮助机器理解人类知识的重要工具,在问答系统、搜索引擎、推荐系统中都有着重要的应用。

    c0d4ec4f673f49c71ca768bc1ec8fd6b.png

     关系图谱示例

    关系抽取十八变

    96bd79d1cefefd1fa3534619d2074b53.png

    由于数据和需求的不同,关系抽取这一任务也发展出了许多不同的任务场景。下面简单介绍几种,他们也都被包括在了 OpenNRE 这一工具包中。 句子级别关系抽取顾名思义,句子级别的关系抽取,就是对每一个给定的句子,和在句子中出现的实体,判断他们之间的关系。在这样的设定下,通常会使用人工精标的数据进行训练和测试,如 SemEval 2010 Task8,TACRED,ACE2005 等。OpenNRE 中还提供了一个新的数据集 Wiki80,包含 80 种 Wikidata 关系和 56,000 个句子,与以往的数据集相比,规模更大。 包级别关系抽取包级别的关系抽取产生于远程监督(Distant Supervision)的设定中。我们都知道,传统的机器学习方法需要大量数据,而标注数据费时费力,因此研究者们提出了远程监督这一方法,通过将知识图谱中的关系三元组与文本对齐,自动进行标注。然而这一方法也带来了大量的噪声数据,为了减小噪声的影响,多样本多标签(multi-instance multi-label)的方法被引入,模型不再对单个句子进行分类,而是对包含相同实体对的句子集(称为包)进行分类。 少次学习关系抽取少次学习(Few-Shot)是一种探索如何让模型快速适应新任务的设定,通过学习少量的训练样本,即可获得对新类型事物的分类能力。刘知远老师组发布的数据集 FewRel 正是进行了这方面的探索。 篇章级别的关系抽取:相比于针对句子的关系抽取,篇章级别的关系抽取难度更大,但包含的信息也更丰富。要想在这方面做的更好,就需要模型具有一定的推理、指代消解的能力。这一领域的代表数据集是同样来自刘知远老师组的DocRED(https://github.com/thunlp/DocRED)。 上述任务场景基本涵盖了目前关系抽取领域的最新进展,OpenNRE 也提供了较为便利的接口以支持上述场景的进一步工作研究。

    上手教程:如何使用OpenNRE

    OpenNRE 的使用十分简单,首先 git clone 项目并安装依赖:

    git clone https://github.com/thunlp/OpenNRE.git
    pip install -r requirements.txt

    随后在目录下打开 Python,并 import opennre:

    >>> import opennre

    可以使用 get_model 命令加载预训练模型:

    >>> model = opennre.get_model('wiki80_cnn_softmax')

    这是一个在 wiki80 数据集上进行训练的句子级别的 CNN 模型,可以在 80 个关系上对句子进行分类。随后我们可以用 infer 函数进行预测:

    >>> model.infer({'text''He was the son of Máel Dúin mac Máele Fithrich, and grandson of the high king Áed Uaridnach (died 612).''h': {'pos': (1846)}, 't': {'pos': (7891)}})
    ('father'0.5108704566955566)

    可以看到模型正确推理出了关系 father,并给出了模型预测的置信度。

    关于 OpenNRE 更详细的说明,可以查看项目主页:

    https://github.com/thunlp/OpenNRE

    或文档:

    https://opennre-docs.readthedocs.io/en/latest/

    关于作者

    OpenNRE 由孙茂松教授领导的清华大学自然语言处理实验室(THUNLP)师生研发维护。目前 THUNLP 的 Github 主页(https://github.com/thunlp)已有 92 个项目,其中有许多高星项目。

    378d59c4ecf66a690fbd1d8d63fca089.png

    OpenNRE 项目的两位主要作者——高天宇(https://gaotianyu.xyz/about/)和韩旭(https://thucsthanxu13.github.io/)都是 THUNLP 实验室刘知远老师的学生。

    其中,高天宇是大四的本科生,韩旭是博士三年级的学生。从主页上可以看出,两人的研究方向均为自然语言处理、信息抽取、图谱表示和机器学习。其中,高天宇作为大四的本科生,已经在相关领域国际会议上发表了三篇论文;而韩旭除了在相关领域发表多篇论文外,也是 OpenNRE、OpenKE 和 FewRel 等多个开源项目的主要开发者与参与者,在开源社区十分活跃。更多的信息可以参考作者个人主页以及项目文档。

    3a0cbb6c89dfed1e9d401fb8ee1e8fc6.png

    点击以下标题查看更多往期内容: 

    • 基于胶囊网络的知识图谱完善和个性化搜索

    • EMNLP 2019:针对短文本分类的异质图注意力网络

    • 变分推断(Variational Inference)最新进展简述

    • BN究竟起了什么作用?一个闭门造车的分析

    • 使用跨领域语言建模的跨领域命名实体识别

    • 从语言模型到Seq2Seq:Transformer如戏

    464780f50a74a82d25eff43845506302.gif#投 稿 通 道#

     让你的论文被更多人看到 

    如何才能让更多的优质内容以更短路径到达读者群体,缩短读者寻找优质内容的成本呢?答案就是:你不认识的人。

    总有一些你不认识的人,知道你想知道的东西。PaperWeekly 或许可以成为一座桥梁,促使不同背景、不同方向的学者和学术灵感相互碰撞,迸发出更多的可能性。 

    PaperWeekly 鼓励高校实验室或个人,在我们的平台上分享各类优质内容,可以是最新论文解读,也可以是学习心得技术干货。我们的目的只有一个,让知识真正流动起来。

    来稿标准:

    • 稿件确系个人原创作品,来稿需注明作者个人信息(姓名+学校/工作单位+学历/职位+研究方向) 

    • 如果文章并非首发,请在投稿时提醒并附上所有已发布链接 

    • PaperWeekly 默认每篇文章都是首发,均会添加“原创”标志

    ? 投稿邮箱:

    • 投稿邮箱:hr@paperweekly.site 

    • 所有文章配图,请单独在附件中发送 

    • 请留下即时联系方式(微信或手机),以便我们在编辑发布时和作者沟通

    ?

    现在,在「知乎」也能找到我们了

    进入知乎首页搜索「PaperWeekly」

    点击「关注」订阅我们的专栏吧

    关于PaperWeekly

    PaperWeekly 是一个推荐、解读、讨论、报道人工智能前沿论文成果的学术平台。如果你研究或从事 AI 领域,欢迎在公众号后台点击「交流群」,小助手将把你带入 PaperWeekly 的交流群里。

    cf3c7055269d18526a0af0d06dd1b69b.gif

    ▽ 点击 | 

    展开全文
  • OpenNRE 我们有一个DEMO网站( )。 试试看! OpenNRE是一个开源且可扩展的工具包,它提供了用于实现关系提取模型的统一框架。 该软件包是为以下人群设计的: 关系提取的新知识:我们提供了手工教程和详细文档,...
  • d:\work\tools\opennre\opennre\pretrain.py", line 138, in get_model max_length=80, pretrain_path=os.path.join(root_path, 'pretrain\bert-base-uncased')) File "d:\work\tools\...
  • import opennre的是出现如下错误: <code>Traceback (most recent call last): File "<stdin>", line 1, in <module> File "/home/lukuan/lk_git/OpenNRE/opennre/__init__.py", line...
  • OpenNRE是清华大学推出的开源关系抽取框架,针对命名实体识别,句子级别的关系抽取,远程监督(包级别的关系抽取),文档级别的关系抽取以及 few-shot 任务均有实现。其模块化的设计可以大幅度减少不必要的代码重写...

    0 前言

    OpenNRE是清华大学推出的开源关系抽取框架,针对命名实体识别,句子级别的关系抽取,远程监督(包级别的关系抽取),文档级别的关系抽取以及 few-shot 任务均有实现。其模块化的设计可以大幅度减少不必要的代码重写。

    本文将对OpenNRE整体架构进行介绍,并重点解读OpenNRE中针对远程监督任务的模型 PCNN + ATT :《Neural Relation Extraction with Selective Attention over Instances》。

    ps:OpenNRE不支持 Windows ,在 Windows 环境下需要改很多路径,非常不方便,建议在 linux 环境下使用。

    1 OpenNRE整体架构

    OpenNRE在实现时,将关系抽取的框架划分成不同的模块,这使得在实现新的模型时,通常秩序修改Model和Encoder部分即可,其他部分不需要太大的改动即可使用,大大的提升了实现模型的效率。

    在这里插入图片描述

    在DataLoader模块中,针对不同的任务,实现了不同的读取策略和DataSet类;

    在Encoder模块中,实现了各个模型获得关系向量表示的步骤。如用 PCNN+最大池化 得到关系向量表示,BERT模型的特殊标记 [CLS] 作为关系向量表示,将两个实体前面插入特殊标记 [E1start],[E2start][E_{1start}], [E_{2start}] ,并将这两个特殊标记的隐藏向量拼接作为关系向量表示(BERTem模型)等。这里对于BERTem模型具体细节不是很清楚的话可以看一下我之前解读BERTem论文与源码的博客。
    BERTem:https://blog.csdn.net/xiaowopiaoling/article/details/105931134
    我后续也会出解读OpenNRE中使用BERT进行关系抽取的源码。

    在Model模块中,实现了在获取关系向量表示后的分类策略。如普通的全连接加softmax,远程监督的将一个包中所有的关系向量平均作为包的关系向量表示再过全连接和softmax,以及本文将要讲解的对于包中的实例应用attention策略后得到向量表示再进行分类等。

    再Train Method 和 Eval Method 中是一些比较套路化的训练步骤,在实现模型时将其稍加改动即可拿来使用,非常方便。

    Module 模块中实现了一些基础模块,如cnn,rnn,lstm,以及处理策略如平均池化,最大池化等,也是可以直接拿来用的。

    FrameWork模块对上述所有模块进行集成,包括普通句子级别的关系抽取流程 sentence_re ,以及远程监督包级别的关系抽取 bag_re 等。

    2 PCNN+ATT 模型架构

    下面,我们将针对远程监督的 PCNN+ATT 模型,来解读一下模型实现的细节。

    2.1 PCNN Encoder

    对于模型中 PCNN 部分,主要流程就是先将文本转化成词嵌入与位置嵌入后,再过卷积神经网路,对于得到的结果,按照实体位置分成第一个实体之前,两个实体之间,第二个实体之后三个部分并分别最大池化。模型图如下:

    在这里插入图片描述

    这里对于模型细节感兴趣的可以看一下我之前的博客。
    PCNN:https://blog.csdn.net/xiaowopiaoling/article/details/106120543

    下面我们来看一下 PCNN encoder 的代码:

    
            self.drop = nn.Dropout(dropout)
            self.kernel_size = kernel_size
            self.padding_size = padding_size
            self.act = activation_function
        
            self.conv = nn.Conv1d(self.input_size, self.hidden_size, self.kernel_size, padding=self.padding_size)
            self.pool = nn.MaxPool1d(self.max_length)
            self.mask_embedding = nn.Embedding(4, 3)
            self.mask_embedding.weight.data.copy_(torch.FloatTensor([[0, 0, 0], [1, 0, 0], [0, 1, 0], [0, 0, 1]]))
            self.mask_embedding.weight.requires_grad = False
            self._minus = -100
    
            self.hidden_size *= 3
    
        def forward(self, token, pos1, pos2, mask):
            """
            Args:
                token: (B, L), index of tokens
                pos1: (B, L), relative position to head entity
                pos2: (B, L), relative position to tail entity
            Return:
                (B, EMBED), representations for sentences
            """
            # Check size of tensors
            if len(token.size()) != 2 or token.size() != pos1.size() or token.size() != pos2.size():
                raise Exception("Size of token, pos1 ans pos2 should be (B, L)")
            x = torch.cat([self.word_embedding(token), 
                           self.pos1_embedding(pos1), 
                           self.pos2_embedding(pos2)], 2) # (B, L, EMBED)
            x = x.transpose(1, 2) # (B, EMBED, L)
            x = self.conv(x) # (B, H, L)
    
            mask = 1 - self.mask_embedding(mask).transpose(1, 2) # (B, L) -> (B, L, 3) -> (B, 3, L)
            pool1 = self.pool(self.act(x + self._minus * mask[:, 0:1, :])) # (B, H, 1)
            pool2 = self.pool(self.act(x + self._minus * mask[:, 1:2, :]))
            pool3 = self.pool(self.act(x + self._minus * mask[:, 2:3, :]))
            x = torch.cat([pool1, pool2, pool3], 1) # (B, 3H, 1)
            x = x.squeeze(2) # (B, 3H)
            x = self.drop(x)
    
            return x
    
    

    这里的注释其实也非常清楚了,其中 B 是batch_size,L 是 sequence_len ,H 是输出通道数,即有多少个卷积核(这里为230)。首先将文本的词嵌入和位置嵌入连接,这里位置嵌入是根据一个词与两个实体之间的相对位置获得的,所以有两个,示例如下:

    在这里插入图片描述
    连接后,我们再过一个卷积层,得到 shape 为 (B, H, L) 的矩阵。

    之后我们采取利用mask进行分段最大池化的策略,这里也是模型非常巧妙地地方。对于一个句子地某个词,如果这个词的位置在第一个实体之前,那么mask相应位置上被置为1,如果在两个实体之间被置为2,第二个实体之后被置为3,用与补齐句子的0填充被置为0。

    通过mask_embedding,mask中文本的位置0,1,2,3分别被映射成[0, 0, 0], [1, 0, 0], [0, 1, 0], [0, 0, 1]。当执行 mask = 1 - self.mask_embedding(mask).transpose(1, 2) 时,四种mask变为 [1, 1, 1], [0, 1, 1], [1, 0, 1], [1, 1, 0]。对于根据实体位置分成的三个段,在每个段的池化过程中,shape 为 (B, H, L) 的 x 将会与 shape 为(B, 1, L) 的 self._minus * mask[:, 0:1, :] 相加,即当前段中元素值不受影响,而其它两个段所有元素都会因被减掉100而不被计算,这样就使得最大池化的过程在一个段上进行。重复三次操作,我们便可以得到对三个段分别进行最大池化的结果。将其拼接后我们即可得到关系的向量表示。

    2.2 Bag Attention

    对于模型中 Attention 的部分,我们先来看一下模型图:

    在这里插入图片描述

    远程监督(distant supervision)利用知识图谱的实体以及对应的关系对未标注文本进行回标,如果未标注文本中包含了一个知识图谱中具有某种关系的实体对,那么就假定这个文本也描述了相同的关系。通过这种标注策略虽然可以获得大量数据,但同时也会因为假设性太强而一如很多噪声数据(因为包含一个实体对的文本不一定描述了对应的关系)。

    解决远程监督错误标注所带来的噪声问题,我们通常使用多示例学习(Multi-instance Learning)的方法,即将多个数据打包成一个 bag ,bag 中所有句子都含有相同的实体对。对于模型图中,一个 bag 中有 ii 个实例,句子 m1,m2,...,mim_1,m_2,...,m_i 经过上面 PCNN Encoder 后获得了其对应的关系向量表示 x1,x2,...,xi\mathbf x_1,\mathbf x_2,...,\mathbf x_i (这里为了防止混淆,将模型图中的 r1,r2,...rir_1,r_2,...r_i 替换为了 x1,x2,...,xi\mathbf x_1,\mathbf x_2,...,\mathbf x_i ),对于 bag 的关系向量表示,我们通过加权平均获得,即:

    s=iαixi\mathbf s=\sum_i {\alpha_i} \mathbf x_i

    得到 bag 的向量表示 s\mathbf s 后,再过全连接加softmax分类即可。

    那么这个权重 α\alpha 应该如何获得呢?有如下三种比较思路:

    1.At Least One。这种思路基于一个假设:对于一个 bag 中的示例,至少有一个示例是标注正确的。假设一个 bag 的标签为 i,即这个包的实体描述了第 i 个关系,我们就选择包中示例预测关系为 i 概率最高的那个示例作为 bag 的关系向量表示。在这种情况下,被选择的示例权重 α\alpha 为1,而其余都为0 。这种思路缓解了数据中含有噪声的问题,但同时也造成了大量的数据浪费。

    2.平均。对于一个包中的关系向量表示 x1,x2,...,xi\mathbf x_1,\mathbf x_2,...,\mathbf x_i ,我们将其以一种非常简单的方式加权,即 bag 种每一个示例的权重都是 1n1\over n 。这样虽然可以尽可能地利用包中的信息,但没有解决远程监督错误标注带来的噪声问题。

    3.Attention机制。设 bag 标签的关系向量表示为 r\mathbf r注意,这里非常容易混淆,前面的提到的 bag 中示例的关系表示为 xi\mathbf x_i ,bag 的关系向量表示为 r\mathbf r,这两个向量都是每次计算得到的,而这里 bag 标签关系的向量表示 rr 暂时可以看作从 embedding 中获得的,在后面我们会详细讲述),对于 bag 中的示例 ii ,我们计算其关系向量表示 xi\mathbf x_i 与 bag 标签的关系向量表示 rr 的匹配度 eie_i 。在PCNN+ATT 的原文种,eie_i 的计算公式如下:

    ei=xiAre_i=\mathbf x_i\mathbf A \mathbf r

    其中 A\mathbf A 是加权对角矩阵。而 OpenNRE 修改了计算公式,改为了计算两个向量之间的点积,具体如下:

    ei=xire_i=\mathbf x_i \cdot \mathbf r

    通过当前关系的匹配度 eie_i 占全部的比重,我们就可以得到权重 αi\alpha_i(也就是softmax) :

    αi=exp(ei)kexp(ek)\alpha_i= {\exp(e_i)\over\sum_k \exp(e_k)}

    看到这里我们可能会有两个问题,一个是 bag 标签关系的向量表示 rr 如何得到,另一个是为什么 OpenNRE 要如此修改计算公式。

    首先,对于 bag 标签关系的向量表示 rr ,在得到 bag 的向量表示 s\mathbf s 后,我们使用全连接加softmax进行分类分类。而 bag 标签关系的向量表示 rr 就是通过这个全连接层中的权重矩阵按照类似于 embedding 层以下标索引的方式得到的。为什么全连接层的权重矩阵可以作为关系向量表示呢?我们来看一下我们使用全连接层分类时矩阵乘法的运算过程,其中 S\mathbf S 是一个 shape 为(batch_size=2, hidden_state=3)的 bag 的关系向量表示,R\mathbf R 是 shape 为(hidden_state=3, num_relation=2)的全连接层的权重,O\mathbf O 为分类结果(实际中还需要加上 bias,这里为了解释原理暂时不考虑)。

    S=[a1,1a1,2a1,3a2,1a2,2a2,3]\mathbf S = \begin{bmatrix} a_{1,1} & a_{1,2} &a_{1,3} \\ a_{2,1} &a_{2,2} &a_{2,3} \end{bmatrix}

    R=[b1,1b1,2b2,1b2,2b3,1b3,2]\mathbf R=\begin{bmatrix} b_{1,1}&b_{1,2}\\b_{2,1}&b_{2,2}\\b_{3,1}&b_{3,2} \end{bmatrix}

    O=SR=[a1,1b1,1+a1,2b2,1+a1,3b3,1a1,1b1,2+a1,2b2,2+a1,3b3,2a2,1b1,1+a2,2b2,1+a2,3b3,1a2,1b1,2+a2,2b2,2+a2,3b3,2]\mathbf O=\mathbf S\cdot \mathbf R=\begin{bmatrix} a_{1,1}b_{1,1}+a_{1,2}b_{2,1}+a_{1,3}b_{3,1}&a_{1,1}b_{1,2}+a_{1,2}b_{2,2}+a_{1,3}b_{3,2}\\a_{2,1}b_{1,1}+a_{2,2}b_{2,1}+a_{2,3}b_{3,1}&a_{2,1}b_{1,2}+a_{2,2}b_{2,2}+a_{2,3}b_{3,2} \end{bmatrix}

    我们可以看到,在分类的过程中,对于一个 bag 的向量表示 s\mathbf s ,即 S\mathbf S 中的一行,我们相当于用其与全连接层权重 R\mathbf R 的每一列都求了一个点积,将点积得到的值作为当前 bag 与相应关系的匹配度,经过softmax后作为这个 bag 描述相应关系的概率。这就解释了 OpenNRE 采用点积的形式来计算匹配度 eie_i 的依据。也正因如此,我们可以把全连接层权重 R\mathbf R 的每一列看作相应关系的向量表示 r\mathbf r 。在计算 eie_i 时,我们只需使用类似于 embedding 的形式,将对应的关系向量 r\mathbf r 取出即可与计算得到的 xi\mathbf x_i 计算点积,从而得到匹配度 eie_i

    至此,模型的 attention 机制已经非常清晰了,下面我们来看一下这部分的源码:

    
            if mask is not None:
                rep = self.sentence_encoder(token, pos1, pos2, mask) # (nsum, H) 
    		if train:
    			if bag_size > 0:
                    batch_size = label.size(0)
                    query = label.unsqueeze(1) # (B, 1)
                    att_mat = self.fc.weight.data[query] # (B, 1, H)
                    rep = rep.view(batch_size, bag_size, -1)
                    att_score = (rep * att_mat).sum(-1) # (B, bag)
                    softmax_att_score = self.softmax(att_score) # (B, bag)
                    bag_rep = (softmax_att_score.unsqueeze(-1) * rep).sum(1) # (B, bag, 1) * (B, bag, H) -> (B, bag, H) -> (B, H)
                bag_rep = self.drop(bag_rep)
                bag_logits = self.fc(bag_rep) # (B, N)
    
    

    这里的 sentence_encoder 就是 PCNN ,rep 即获得的 bag 中所有示例的向量表示,shape 为(batch_size * bag_size, hidden_state)。接下来我们从全连接层中取出 label 对应的关系向量 r\mathbf r ,也就是 att_mat ,shape 为(batch_size, 1, hidden_state),同时将 rep 的 shape 变为(batch_size, bag_size, hidden_state),再将 rep 与 att_mat 中的元素一一对应相乘,这时会进行广播运算,对于得到的结果在最后一个维度求和,就相当于求得点积。之后再通过 eie_i 也就是 softmax 得到对应权重的 αi\alpha_i ,将其与关系向量表示 rep 按元素意义对应相乘并求和,即进行了加权平均运算。最后过一个 dropout 和全连接即可得到分类结果。

    PCNN+ATT 模型的损失采用了交叉熵,其训练也是比较套路化的,在此就不过多赘述了,对于更多实现细节有兴趣的话可以阅读 OpenNRE 的源码。

    结语

    OpenNRE 是一个优秀的关系抽取框架,通过将关系抽取的框架划分成不同的模块,大大的提升了实现模型的效率。同时由于集成了许多关系抽取模型,使得不同模块之间可以自由组合,极大方便了日后基于 OpenNRE 的拓展与研究。

    参考资料

    OpenNRE 论文:
    https://www.aclweb.org/anthology/D19-3029.pdf
    OpenNRE 源码:
    https://github.com/thunlp/OpenNRE
    PCNN 论文:
    https://www.aclweb.org/anthology/D15-1203.pdf
    PCNN 参考博客:
    https://blog.csdn.net/xiaowopiaoling/article/details/106120543
    PCNN+ATT 论文:
    https://www.researchgate.net/publication/306093646_Neural_Relation_Extraction_with_Selective_Attention_over_Instances

    展开全文
  • OpenNRE(https://github.com/thunlp/OpenNRE.git)是清华大学自然语言处理实验室推出的一款开源的神经网络关系抽取工具包,包括了多款...
  • thunlp opennre安装

    2020-12-30 10:03:31
    在ubuntu下安装 python用3.8即可 FAQ: 鼠标变成十字:kill掉import进程 ctrl+alt+t ps -A|grep import kill -9 11292
  • github项目OpenNRE通过git clone指令克隆到本地之后,需要对项目所需的包进行配置。 项目中包含一个requirements.txt文件,通过指令pip install -r requirements.txt可以批量安装。 要知道ubuntu自带的有python的...
  • 在清华大学开源的OpenNRE项目基础上实现中文实体关系识别github项目地址,点我一、中文关系抽取使用哈工大,BERT-wwm,中文bert,在20w中文人物关系数据上的准确率达到0.97实现过程实现过程十分简单,如下:1)token...
  • 事件抽取是理解语言的一个重要基础,在金融领域尤其有用。在应用NLP技术前,很多金融从业人员真的是靠人盯新闻、公告。你想想,从那么长的一篇新闻或公告中找出一些风险信号或营销机会真的是费时费力。...
  • 一、远程监督简介 远程监督的英文名称Distant Supervision,是目前关系抽取中比较常见的一类做法。该方法由 M Mintz 大佬于ACL2009上首次提出,它既不是单纯的传统意义上的监督语料,当然也不是无监督。...
  • 作者 | 李秋键责编 | Carol封图 |区块链大本营(blockchain_camp)语义解析作为自然语言处理的重要方面,其主要作用如下:在词的层次上,语义分析的基本任务是进行词义消歧;在句子层面上,语义角色标注是所关心的问题...
  • 作者 | 李秋键责编 | Carol封图 | 区块链大本营(blockchain_camp)语义解析作为自然语言处理的重要方面,其主要作用如下:在词的层次上,语义分析的基本任务是进行词义消歧;在句子层面上,语义角色标注是所关心的...
  • 作者 | 李秋键责编 | Carol来源 | AI科技大本营(ID:rgznai100)语义解析作为自然语言处理的重要方面,其主要作用如下:在词的层次上,语义分析的基本任务是进行词义消歧;在句子层面上,语义角色标注是所关心的问题;...
  • 第十九届中国计算语言学大会(The Nineteenth China National Conference on Computational Linguistics, CCL 2020)于2020年10月30日—11月1日在线上举行,数字出版技术国家重点实验室研究人员参加了大会,并在大会上...
  • Must-read papers on NRE NRE: Neural Relation Extraction. Contributed by Tianyu Gao and Xu ...We released OpenNRE, an open-source framework for neural relation extraction. This repository provides se...
  • Bert+attention -2

    2021-01-07 14:50:15
    from opennre import encoder, model, framework import sys import os import argparse import logging <p>parser = argparse.ArgumentParser() parser.add_argument('--pretrain_path', default=&...

空空如也

空空如也

1 2 3 4 5
收藏数 93
精华内容 37
关键字:

opennre