NLP学习————实现一个BERT(简记)
本文主要内容是介绍了BERT的代码结构、具体实现与原理,对BERT的一些简记
内容包括以下几个部分:
- BERT Tokenization 分词模型(BertTokenizer)
- BERT Model 本体模型(BertModel)
- BertEmbeddings
- BertEncoder
- BertLayer
- BertAttention
- BertIntermediate
- BertOutput
- BertPooler
本文内容的结构图如下:
具体的内容如下
1. BERT Tokenization 分词模型(BertTokenizer)
1)Tokenization分词-BertTokenizer:基于BasicTokenizer和WordPieceTokenizer的分词器 a)BasicTokenizer负责处理的第一步——按标点、空格等分割句子,并处理是否统一小写,以 及清理非法字符。 (1)对于中文字符,通过预处理(加空格)来按字分割; (2)同时可以通过never_split指定对某些词不进行分割; (3)这一步是可选的(默认执行)。 b)WordPieceTokenizer在词的基础上,进一步将词分解为子词(subword)。 (1)subword 介于 char 和 word 之间,既在一定程度保留了词的含义,又能够照顾到英 文中单复数、时态导致的词表爆炸和未登录词的 OOV(Out-Of-Vocabulary)问题,将词根 与时态词缀等分割出来,从而减小词表,也降低了训练难度; (2)例如,tokenizer 这个词就可以拆解为“token”和“##izer”两部分,注意后面一个词的 “##”表示接在前一个词后面。 2. BERT Model 本体模型(BertModel) 组成: 1. embeddings,即BertEmbeddings类的实体,根据单词符号获取对应的向量表示; 2. encoder,即BertEncoder类的实体; 3. pooler,即BertPooler类的实体,这一部分是可选的。 补充: 剪枝是一个复杂的操作,需要将保留的注意力头部分的 Wq、Kq、Vq 和拼接后全连接部分的权重拷贝到一个新的较小的权重矩阵(注意先禁止 grad 再拷贝),并实时记录被剪掉的头以防下标出错。具体参考BertAttention部分 的prune_heads方法.**
2.1 BertEmbeddings
组成:包含三个部分求和得到:
1) word_embeddings,上文中 subword 对应的嵌入。 2) token_type_embeddings,用于表示当前词所在的句子,辅助区别句子与 padding、句子对间的差异。 3) position_embeddings,句子中每个词的位置嵌入,用于区别词的顺序。和 transformer 论文中的设计不同,这一块是训练出来的,而不是通过 Sinusoidal 函数计算得到的固定嵌入。一般认为这种实现不利于拓展性(难以直接迁移到更长 的句子中)。 ->>> 三个 embedding 不带权重相加,并通过一层 LayerNorm+dropout 后输出,其大小 为(batch_size, sequence_length, hidden_size)。 2.2 BertEncoder 组成:包含多层 BertLayer,这一块本身没有特别需要说明的地方,不过有一个细节值 得参考:利用 gradient checkpointing 技术以降低训练时的显存占用。 - BertLayer - BertAttention - BertSelfAttention - BertSelfOutput - BertIntermediate - BertOutput 2.3 BertPooler 这一层只是简单地取出了句子的第一个token,即[CLS]对应的向量,然后过一个全连接层 和一个激活函数后输出:(这一部分是可选的,因为pooling有很多不同的操作)
|