# t4

## 1 BertTokenizer

* 组成结构：BasicTokenizer和WordPieceTokenizer
* BasicTokenizer主要作用是做一些基础的大小写、unicode转换、标点符号分割、小写转换、中文字符分割、去除重音符号等操作，最后返回的是关于词的数组（中文是字的数组）
* WordPieceTokenizer主要作用基于vocab切词
* FullTokenzier

  这个基本上就是利用basic和wordpiece来切分。用于bert训练的预处理。基本就一个tokenize方法。不会有encode\_plus等方法。
* PretrainTokenizer 这个则是bert的base类，定义了很多方法(convert\_ids\_to\_tokens)等。 后续的BertTokenzier，GPT2Tokenizer都继承自pretrainTOkenizer，下面的关系图可以看到这个全貌。
* BertTokenizer常用方法： 1. from\_pretrained：从包含词表文件（vocab.txt）的目录中初始化一个分词器； 2. tokenize：将文本（词或者句子）分解为子词列表； 3. convert\_tokens\_to\_ids：将子词列表转化为子词对应的下标列表； 4. convert\_ids\_to\_tokens ：与上一个相反； 5. convert\_tokens\_to\_string：将subword列表按“##”拼接回词或者句子； 6. encode：
  * 对于单个句子输入，分解词，同时加入特殊词形成“\[CLS], x, \[SEP]”的结构，并转换为词表对应的下标列表；
  * 对于两个句子输入（多个句子只取前两个），分解词并加入特殊词形成“\[CLS], x1, \[SEP], x2, \[SEP]”的结构并转换为下标列表；
    1. decode：可以将encode方法的输出变为完整句子。

## [2 BertModel（BERT Model 本体模型）](https://relph1119.github.io/my-team-learning/#/transformers_nlp28/task04?id=_2-bertmodel%EF%BC%88bert-model-%E6%9C%AC%E4%BD%93%E6%A8%A1%E5%9E%8B%EF%BC%89)

* 组成结构：主要是Transformer-Encoder结构
  1. embeddings：BertEmbeddings类的实体，根据单词符号获取对应的向量表示；
  2. encoder：BertEncoder类的实体；
  3. pooler：BertPooler类的实体，这一部分是可选的
* BertModel常用方法：
  1. get\_input\_embeddings：提取 embedding 中的 word\_embeddings，即词向量部分；
  2. set\_input\_embeddings：为 embedding 中的 word\_embeddings 赋值；
  3. \_prune\_heads：提供了将注意力头剪枝的函数，输入为{layer\_num: list of heads to prune in this layer}的字典，可以将指定层的某些注意力头剪枝。

### [2.1 BertEmbeddings](https://relph1119.github.io/my-team-learning/#/transformers_nlp28/task04?id=_21-bertembeddings)

对于输入word\_ids，返回embedding table。可以选用one-hot或者tf.gather()

* 输出结果：通过word\_embeddings、token\_type\_embeddings、position\_embeddings三个部分求和，并通过一层 LayerNorm+Dropout 后输出得到，其大小为(batch\_size, sequence\_length, hidden\_size)
* word\_embeddings：子词(subword)对应的embeddings
* token\_type\_embeddings：用于表示当前词所在的句子，区别句子与 padding、句子对之间的差异
* position\_embeddings：表示句子中每个词的位置嵌入，用于区别词的顺序

> 使用 LayerNorm+Dropout 的必要性： 通过layer normalization得到的embedding的分布，是以坐标原点为中心，1为标准差，越往外越稀疏的球体空间中

### [2.2 BertEncoder](https://relph1119.github.io/my-team-learning/#/transformers_nlp28/task04?id=_22-bertencoder)

* 技术拓展：梯度检查点（gradient checkpointing），通过减少保存的计算图节点压缩模型占用空间

#### [2.2.1 BertAttention](https://relph1119.github.io/my-team-learning/#/transformers_nlp28/task04?id=_221-bertattention)

* BertSelfAttention
  1. 初始化部分：检查隐藏层和注意力头的参数配置倍率、进行各参数的赋值
  2. 前向传播部分：
     * multi-head self-attention的基本公式：$\text{MHA}(Q, K, V) = \text{Concat}(\text{head}\_1, \ldots, \text{head}\_h)W^O \ \text{head}\_i = \text{SDPA}(\text{QW}\_i^Q, \text{KW}\_i^K, \text{VW}\_i^V) \ \text{SDPA}(Q, K, V) = \text{softmax}(\frac{Q \cdot K^T}{\sqrt{d\_k}}) \cdot V$
     * transpose\_for\_scores：用于将 hidden\_size 拆成多个头输出的形状，并且将中间两维转置进行矩阵相乘
     * torch.einsum：根据下标表示形式，对矩阵中输入元素的乘积求和
     * positional\_embedding\_type：
       * absolute：默认值，不用进行处理
       * relative\_key：对key layer处理
       * relative\_key\_query：对 key 和 value 都进行相乘以作为位置编码
* BertSelfOutput：

    前向传播部分使用LayerNorm+Dropout组合，残差连接用于降低网络层数过深，带来的训练难度，对原始输入更加敏感。

#### [2.2.2 BertIntermediate](https://relph1119.github.io/my-team-learning/#/transformers_nlp28/task04?id=_222-bertintermediate)

* 主要结构：全连接和激活操作
* 全连接：将原始维度进行扩展，参数intermediate\_size
* 激活：激活函数默认为 gelu，使用一个包含tanh的表达式进行近似求解

#### [2.2.3 BertOutput](https://relph1119.github.io/my-team-learning/#/transformers_nlp28/task04?id=_223-bertoutput)

主要结构：全连接、dropout+LayerNorm、残差连接（residual connect）

### [2.3 BertPooler](https://relph1119.github.io/my-team-learning/#/transformers_nlp28/task04?id=_23-bertpooler)

主要作用：取出句子的第一个token，即\[CLS]对应的向量，然后通过一个全连接层和一个激活函数后输出结果。
