GEAR(基于图的证据整合与推理)ACL2019论文及代码阅读笔记

整理一下阅读论文代码后的笔记

代码获取时间为2019.09.30

基本pipeline

文档检索->句子检索->事实验证

  • 文档检索:
    • 分析句法树得到潜在实体queries
    • 使用Wikipedia API查询,得到文档集合,并使用词条名和claim的word overlap进行过滤
  • 句子检索:
    • 使用ESIM模型,设计了判断句子相关性的任务,损失函数使用Hinge loss: ∑ m a x ( 0 , 1 + s n − s p ) \sum{max(0, 1 + s_n - s_p)} max(0,1+snsp),此损失函数,学习目标是负样本相关分数 s n s_n sn尽可能低,正样本相关分数 s p s_p sp尽可能高,这样整体模型loss才会趋于0
    • 使用阈值(数量阈值 6 6 6与相关分数阈值 τ \tau τ)过滤
  • 事实验证:
    • 特征提取(句子建模):基本思想是使用BERT模型[CLS]位置的隐向量作为输入序列的编码,获取evidence文本编码时,输入中也包含了claim,如下:
      e i = B E R T ( e i , c ) c = B E R T ( c ) {\rm{e}}_i = BERT(e_i, c) \\ {\rm{c}} = BERT(c) ei=BERT(ei,c)c=BERT(c)

      相关代码:

      # feature_extractor/extractor:87
      #
      # The convention in BERT is:
      # (a) For sequence pairs:
      #  tokens:   [CLS] is this jack ##son ##ville ? [SEP] no it is not . [SEP]
      #  type_ids: 0   0  0    0    0     0       0 0    1  1  1  1   1 1
      # (b) For single sequences:
      #  tokens:   [CLS] the dog is hairy . [SEP]
      #  type_ids: 0   0   0   0  0     0 0
      

      通过设置不同标识来区分单句还是双句,之后将tokens转换为bert中的id,并通过1-0 padding得到mask,并丢给Bert预训练模型获取句子表示(特征向量),字典形式保存到文件

    这部分了解到的新内容:
    模型并行:torch.nn.parallel.DistributedDataParallel,torch.nn.DataParallel(后者是简单的单机多卡,数据并行?)
    数据传递:TensorDataset,沿第一个维度取各个传入tensor的数据

    • 特征加载:主要是对于候选证据个数做了限制,默认阈值为5。不足5条时,做zero-padding

    • 模型:分为推理和整合两个阶段,推理是self-attention,整合是采用claim-aware的attention或者max-pooling或mean—pooling
      推理中的每一步都是一个全连接attention,每一步即stacking的一层,论文中结果表明,nlayer=2时实验效果略好。由于每层输入输出尺寸都相同(获取的句子表示tensor shape都一样),因此forward的时候,循环实现步进

      # gear/models.py:58
      
      self.attentions = [AttentionLayer(nins, nfeat) for _ in range(nlayer)]
      
      # gear/models.py:76
      # 这里input是每个数据组中evidence的表示,claim是单独传入的
      for i in range(self.nlayer):
          inputs = self.attentions[i](inputs)
      

      对于一个数据实例,其包含nins个证据表示,在特定某层推理时,这nins个向量,都要和全体组内向量做attention操作。SelfAttentionLayer输入向量长度应当为nhid * 2,因为论文中进行权重分数计算的公式中,首先对attention的query和key进行了concat,没有使用Dot、general两种方法
      p i j = W 1 t − 1 ( R e L U ( W 0 t − 1 ( h i t − 1 ∣ ∣ h j t − 1 ) ) ) p_{ij} = {\rm{W}_{1}^{t-1}}({\rm{ReLU}}({\rm{W}_{0}^{t-1}}({\rm{h}_{i}^{t-1}}||{\rm{h}_{j}^{t-1}}))) pij=W1t1(ReLU(W0t1(hit1hjt1)))
      h i {\rm{h_i}} hi h j {\rm{h_j}} hj p i j p_{ij} pij都是列向量

      # gear/models.py:8
      # self.project对应到上面的公式:线性层、ReLU、线性层,对应矩阵运算
      class SelfAttentionLayer(nn.Module):
          def __init__(self, nhid, nins):
              super(SelfAttentionLayer, self).__init__()
              self.nhid = nhid
              self.nins = nins
              self.project = nn.Sequential(
                  Linear(nhid, 64),
                  ReLU(True),
                  Linear(64, 1)
              )
      # own.repeat是为了下一步的concat操作
      # attention.squeeze 将多个单独的权重值降维成为一个weight向量,又升维和inputs相乘
      # 得到input中每个向量的加权贡献,求和得到own的attention表示
          def forward(self, inputs, index, claims):
              tmp = None
              if index > -1:
                  idx = torch.LongTensor([index]).cuda()
                  own = torch.index_select(inputs, 1, idx)
                  own = own.repeat(1, self.nins, 1)
                  tmp = torch.cat((own, inputs), 2)
              else:
                  claims = claims.unsqueeze(1)
                  claims = claims.repeat(1, self.nins, 1)
                  tmp = torch.cat((claims, inputs), 2)
              # before
              attention = self.project(tmp)
              weights = F.softmax(attention.squeeze(-1), dim=1)
              outputs = (inputs * weights.unsqueeze(-1)).sum(dim=1)
              return outputs
      
      # gear/models.py:41
      # 对每一个query,声明一个attention结构 
      self.attentions = [SelfAttentionLayer(nhid=nhid * 2, nins=nins) for _ in range(nins)]
      
      # gear/models.py:48
      # 所有query的attention        
      outputs = torch.cat([self.attentions[i](inputs, i, None) for i in range(self.nins)], dim=1)
      outputs = outputs.view(inputs.shape)
      

      推理输入输出shape一致,输出的向量是进行过若干层信息传播的句子编码,用claim当query,使用self-attention,得到一个状态向量(或这里选择不再整合claim信息,直接max-pooling、mean-pooling)

      # gear/models:65
      
      self.aggregate = SelfAttentionLayer(nfeat * 2, nins)
      
      # gear/models:80
      
      inputs = self.aggregate(inputs, -1, claims)
      

    这部分了解到的新内容:
    需要掩码操作的时候,torch.index_select可以选择性地挑出需要的某几个维度,一般维度0是batch选择,维度1就是组内数据选择:torch.index_select(batch, 1, some_indices)

    • 训练:训练的损失函数是NLL(负对数似然),在这里等价于交叉熵
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值