BERT模型embedding层和MultHeadedSelfAttention层代码解析

2021SC@SDUSC

embedding层中BERT模型的输入表示是token embedding、segmentation embedding、position embedding的总和。分别的意义是:token符号、segmentation分割、position位置和顺序。

token embedding是将各个词转换成了一定维度上的向量。BERT通常固定维度为768。

segment embedding分割编码,是用来区分上下句子,表示当前词在句子中的位置。

position embedding位置编码(PE),是给模型传递字符输入顺序的信息,给每个单词添加其在句子中的位置的信息,也就是位置信息编码。

简单来说,embedding对句子的处理就是先将一个句子每个单词和字符符号都转化为 向量 ,也就是token embedding,再将这样之后会出现一些分句,为了将它们区分,就给每个分句加上它们的特有分割编码,也就是segment embedding,最后再给每个字符加上特有的位置编码,也就是position embedding,以便分辨或确认他们的顺序和位置。

__init__()定义了三个编码信息。

将三者求和就是模型的输入。

def forward()定义了前向传播时经过embedding层的流程,就是根据句段文本建立矩阵,再分别将得到的token embedding、position embedding、segmention embedding进行求和作为模型输入传递给下一层。

接下来的是MultHeadedSelfAttention层

class MultiHeadedSelfAttention(nn.Module):
    """ Multi-Headed Dot Product Attention """
    def __init__(self, cfg):
        super().__init__()
        self.proj_q = nn.Linear(cfg.dim, cfg.dim)
        self.proj_k = nn.Linear(cfg.dim, cfg.dim)
        self.proj_v = nn.Linear(cfg.dim, cfg.dim)
        self.drop = nn.Dropout(cfg.p_drop_attn)
        self.scores = None # for visualization
        self.n_heads = cfg.n_heads

    def forward(self, x, mask):
        """
        x, q(query), k(key), v(value) : (B(batch_size), S(seq_len), D(dim))
        mask : (B(batch_size) x S(seq_len))
        * split D(dim) into (H(n_heads), W(width of head)) ; D = H * W
        """
        # (B, S, D) -proj-> (B, S, D) -split-> (B, S, H, W) -trans-> (B, H, S, W)
        q, k, v = self.proj_q(x), self.proj_k(x), self.proj_v(x)
        q, k, v = (split_last(x, (self.n_heads, -1)).transpose(1, 2)
                   for x in [q, k, v])
        # (B, H, S, W) @ (B, H, W, S) -> (B, H, S, S) -softmax-> (B, H, S, S)
        scores = q @ k.transpose(-2, -1) / np.sqrt(k.size(-1))
        if mask is not None:
            mask = mask[:, None, None, :].float()
            scores -= 10000.0 * (1.0 - mask)
        scores = self.drop(F.softmax(scores, dim=-1))
        # (B, H, S, S) @ (B, H, S, W) -> (B, H, S, W) -trans-> (B, S, H, W)
        h = (scores @ v).transpose(1, 2).contiguous()
        # -merge-> (B, S, D)
        h = merge_last(h, 2)
        self.scores = scores
        return h

MultHeadedSelfAttention 多头注意力机制

__init__()中用nn.Linear()分别定义了q/k/v接入全连接层的输入和输出的维度,q/k/v之前我们前置知识的时候讲过,分别是输入向量的Query、Key、Value。nn.Dropout(p)是常用的防止过拟合的技术,防止或减轻过拟合,同时可以提升模型鲁棒性。里面有个概率p,p是使某个神经元激活值不参与或置为0的概率。heads是层数,在BERT模型里面一般是12层。

forward()定义了前向传播中Multi-Head Attention层的运行流程这和我们之前讲过的self-attention类似,不过使升级版。也就是将 Scaled Dot-Product Attention的过程执行heads次最后合并起来。 

关于selfattention的计算过程前面有讲到,不过多赘述。

多头注意力机制的公式如下:

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值