SGM: Sequence Generation Model for Multi-Label Classification(用于多标签分类的序列生成模型)

2018年最好的nlp文章,先说结论,有些参考的价值可以分享一下:

总结:

SSG模型细节和实现。

模型图:

    

 Encoder

令  (X1,X2,X3,Xm)为 m 个单词的序列。我们首先通过一个嵌入矩阵 (embedding matrix),把 嵌入成一个稠密的嵌入向量  ,  |V|是词汇表的大小, k 是嵌入向量的维度。

我们使用一个bidirectional LSTM 从两个方向上来读取文本序列 x,并且计算每个单词的隐藏状态:

我们通过连接两个方向上的隐藏状态来得到第  i个单词的最终隐藏状态,

这使得状态具有以第 i 个单词为中心的序列信息。

这里的pack可以去pytorch官网搜一下这个官方定义的函数

pack_padded_sequence

当模型预测不同的标签的时候,并不是所有的单词贡献相同。注意力机制会通过关注文本序列中的不同部分,产生一个上下文向量 (context vector)。

特别的,本文采用的 Attention 是 global attention,什么是global attention,这里我列举一下:

 

 原文中是这么写的,我们可以对照一下:

其中注意力模型用的是加性模型。

 Decoder

这里在序列生成模型的 decode 部分进行了改造,不但考虑了标签间相关性,还自动获取了输入文本的关键信息(Attention机制)

Decoder在第 t 时刻的隐藏状态计算如下:

 其中,[g(yt−1); ct−1]   的意思是g(yt−1)  和  ct−1. g(yt−1) 的连接, g(yt−1)  是标签的嵌入,这里的标签指的是在 yt-1 分布下的最高概率对应的标签。yt-1是在t-时刻在标签空间 L上的概率分布,计算如下

class rnn_decoder(nn.Module):

    def __init__(self, config, embedding=None, use_attention=True):
        super(rnn_decoder, self).__init__()

        self.config = config
        self.hidden_size = config.hidden_size
        self.embedding = embedding if embedding is not None else nn.Embedding(config.tgt_vocab_size, config.emb_size)
        input_size = 2 * config.emb_size if config.global_emb else config.emb_size

        if config.cell == 'gru':
            self.rnn = StackedGRU(input_size=input_size, hidden_size=config.hidden_size,
                                  num_layers=config.dec_num_layers, dropout=config.dropout)
        else:
            self.rnn = StackedLSTM(input_size=input_size, hidden_size=config.hidden_size,
                                   num_layers=config.dec_num_layers, dropout=config.dropout)

        self.linear = nn.Linear(config.hidden_size, config.tgt_vocab_size)

        if not use_attention or config.attention == 'None':
            self.attention = None
        elif config.attention == 'bahdanau':
            self.attention = attention.bahdanau_attention(config.hidden_size, input_size)
        elif config.attention == 'luong':
            self.attention = attention.luong_attention(config.hidden_size, input_size, config.pool_size)
        elif config.attention == 'luong_gate':
            self.attention = attention.luong_gate_attention(config.hidden_size, input_size)
        
        self.dropout = nn.Dropout(config.dropout)
        
        if config.global_emb:
            self.ge_proj1 = nn.Linear(config.emb_size, config.emb_size)
            self.ge_proj2 = nn.Linear(config.emb_size, config.emb_size)
            self.softmax = nn.Softmax(dim=1)

    def forward(self, input, state, output=None, mask=None): 
        embs = self.embedding(input)

        if self.config.global_emb:
            if output is None:
                output = embs.new_zeros(embs.size(0), self.config.tgt_vocab_size)
            probs = self.softmax(output / self.config.tau) #标签
            # 两个张量矩阵相乘,在PyTorch中可以通过torch.matmul函数实现;(embedding.weight)ei表示时刻i 输出对应的 Embedding 的 label
            emb_avg = torch.matmul(probs, self.embedding.weight)
            #H 是 transform gate,用于控制带权平均嵌入的比例
            H = torch.sigmoid(self.ge_proj1(embs) + self.ge_proj2(emb_avg))
            emb_glb = H * embs + (1 - H) * emb_avg  #g(yt-1)=(1-H)*e+H*e
            embs = torch.cat((embs, emb_glb), dim=-1)

        output, state = self.rnn(embs, state)#embs等于ei state貌似是Ct
        if self.attention is not None:
            if self.config.attention == 'luong_gate':
                output, attn_weights = self.attention(output)
            else:
                output, attn_weights = self.attention(output, embs)
        else:
            attn_weights = None
        output = self.compute_score(output)

        if self.config.mask and mask:   #mask softmax
            # 沿一个新维度对输入张量序列进行连接,序列中所有张量应为相同形状;stack 函数返回的结果会新增一个维度,而stack()函数指定的dim参数,就是新增维度的(下标)位置。
            mask = torch.stack(mask, dim=1).long()
            output.scatter_(dim=1, index=mask, value=-1e7)

        return output, state, attn_weights

Global Embedding

 

其中 H 是 transform gate,用于控制带权平均嵌入的比例。所有的  为权重矩阵。通过考虑每一个 label 的概率,模型可以减少先前时间步带来的错误预测的损失。这使得模型预测得更加准确。 

  • 问题: 多标签分类的输出显然是不能重复的。
  • 解决方法: 作者在最终 Softmax 输出的时候引入了  It将已输出的标签剔除。

yt = sof tmax(ot + It)

 的表示如下,如果标签已经被输出了,则 It 为负无穷,

  • 问题: Seq2Seq 中某时刻 t 的输出对时刻 t+1 的输出影响很大,也就是说时刻  出错会对时刻  之后的所有输出造成严重影响。
  • 解决方法: 在多标签分类问题中,我们显然不想让标签间拥有如此强的关联性,于是作者提出 Global Embedding 来解决这个问题。

此外,作者在数据预处理阶段也采用一些技巧。比如,考虑到出现次数更多的标签在标签相关性训练中具有更强的作用,在训练时把标签按照其出现次数进行从高到低排序作为输出序列。这么做的好处是,出现次数更多的标签可以出现 LSTM 的前面,进而更好地指导整个标签的输出。

论文来源:

SGM: Sequence Generation Model for Multi-label Classification

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值