从源码解析 Bert 的 Embedding 模块

31 篇文章 3 订阅
23 篇文章 11 订阅

前文链接->从源码层面,深入理解 Bert 框架

前边从源码层面对BertModel类进行了一个深入的解析,接下来从云源码层面对 BertModel 类中的BertEmbeddings模块进行解析

1. BertEmbeddings 类源码

class BertEmbeddings(nn.Module):
    """Construct the embeddings from word, position and token_type embeddings.
    """
    def __init__(self, config):
        super(BertEmbeddings, self).__init__()
        self.word_embeddings = nn.Embedding(config.vocab_size, config.hidden_size, padding_idx=0)
        self.position_embeddings = nn.Embedding(config.max_position_embeddings, config.hidden_size)
        self.token_type_embeddings = nn.Embedding(config.type_vocab_size, config.hidden_size)

        # self.LayerNorm is not snake-cased to stick with TensorFlow model variable name and be able to load
        # any TensorFlow checkpoint file
        self.LayerNorm = BertLayerNorm(config.hidden_size, eps=1e-12)
        self.dropout = nn.Dropout(config.hidden_dropout_prob)

    def forward(self, input_ids, token_type_ids=None):
        seq_length = input_ids.size(1)
        position_ids = torch.arange(seq_length, dtype=torch.long, device=input_ids.device)
        position_ids = position_ids.unsqueeze(0).expand_as(input_ids)
        if token_type_ids is None:
            token_type_ids = torch.zeros_like(input_ids)

        words_embeddings = self.word_embeddings(input_ids)
        position_embeddings = self.position_embeddings(position_ids)
        token_type_embeddings = self.token_type_embeddings(token_type_ids)

        embeddings = words_embeddings + position_embeddings + token_type_embeddings
        embeddings = self.LayerNorm(embeddings)
        embeddings = self.dropout(embeddings)
        return embeddings

1. __ init __(self, config)函数

我们知道,Bert模型的输入是三个数组,分别是词向量、句向量和位置编码;
__ init __() 函数分别定义三个embedding对象,用于对词向量、句向量和位置编码进行 embedding,对这三种数据进行embedding的参数如下表所示:

名称embedding的数据个数每个token embedding后的维度
词向量词库容量hidden_size(默认768)
句向量每个序列中最多包含几个句子(默认为2)hidden_size(默认768)
位置编码最大序列长度(默认为512)hidden_size(默认768)

这里解释一下 embedding 的本质:

以 word embedding 为例,对于每个词语,最开始都是使用 one-hot 编码来表示,word embedding
的过程就是用一个m维的稠密向量代替 one-hot 编码的过程;word
embedding本质上是建立一个从one-hot编码到m维的稠密向量的映射 word embedding
需要建立一个词向量矩阵,矩阵中的每一行存储一个词对应的词向量;每个词one-hot编码的值=对应词向量在词向量矩阵中的行号;
每个词的词向量最初都是随机生成的,在神经网络训练的过程中,这些词向量会不断优化

然后,定义了 一个LayerNorm函数和一个dropout函数,分别执行层标准化和dropout功能

2. Forward(self, input_ids, token_type_ids=None)函数

Forward函数在PyTorch中是一个比较特殊的函数,具体请参考此文->#深入探究# PyTorch中的 forward() 方法详解
forward函数的第1行代码是获取序列的长度,第2、3行是生成位置编码序列,具体做法是:

首先生成一个0到序列长度的数组,然后使用 unsqueeze()函数将此一维数组变成二维数组,最后使用expandas()函数将数组形状变为 [batch_size,序列长度];关于unsqueeze()函数的具体介绍请参考此文章->#彻底理解# pytorch 中的
squeeze() 和 unsqueeze()函数

然后是检查 token_type_ids 数组是否为 Null,如果不存在则生成一个形状和 input_ids 相同的全零二维数组 [batch_size,序列长度],这表示每个序列数据中只包含一个句子

接下来就是根据 input_ids, token_type_ids,position_ids三个输入分别生成三个embedding数组,最后将三个数组对应位置的元素相加。通过这个操作我们可知,每个token的embedding都是三个embedding相加后的结果

这里解释一下生成position_ids的过程:

bert模型的输入是一个batch的数据,因此也要生成一个batch的position_ids;首先生成一个样本的position_ids,然后使用unsqueeze()和expand_as()函数,增加一个维度并将当前生成的position_ids信息扩展(复制)到一个batch内的其他样本中,换句话说就是生成batch_size个相同的position_ids并组合成一个数组

最后将相加后的 embedding 进行LayerNorm和dropout操作后返回

总结来说,Bert中的embedding模块做的工作就是:生成三个embedding数组并相加,而后进行LayerNorm和dropout操作后返回

接下来将对Bert的BertEncoder和BertPooler模块进行详细的解析:

  1. 从源码解析 Bert 的 BertEncoder 模块
  2. 从源码解析 Bert 的 BertPooler 模块
  • 12
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

energy_百分百

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值