一、BERT原理
BERT取名来自 Bidirectional Encoder Representations from Transformers。架构为:预训练 + fine-tuning(对于特定的任务只需要添加一个输出层)。 1、引言 通过预训练语言模型可显著提高NLP下游任务。限制模型潜力的主要原因在于现有模型使用的都是单向的语言模型,无法充分了解到单词所在的上下文结构。 受完形填空的启发,BERT通过使用 “Masked Language Model” 的预训练目标来缓解单向语言模型的约束。 首先 “Masked Language Model” 会随机屏蔽(masked)15%的token,然后让模型根据上下文来预测被Mask的token(被Mask的变成了标签)。具体,将masked token 位置输出的最终隐层向量送入softmax,来预测masked token。 此外, “Next sentence prediction” 的任务预训练文本对。将 token-level 提升到 sentence-level,以应用不同种类的下游任务。 2、BERT模型 BERT:pre-training 和 fine-tuning,两阶段的步骤。- pre-training 阶段,BERT 在无标记的数据上进行无监督学习;
- fine-tuning 阶段,BERT利用预训练的参数初始化模型,并利用下游任务标记好的数据进行有监督学习,并对所有参数进行微调。
![0](/i/l/?n=23&i=blog/1596082/202304/1596082-20230415231550893-826008808.png)
![0](/i/l/?n=23&i=blog/1596082/202304/1596082-20230415231550940-978612517.png)
![0](/i/l/?n=23&i=blog/1596082/202304/1596082-20230415231550828-368670208.png)
- Token Embeddings 采用的 WordPiece Embedding,共有 30000 个 token。每个 sequence 会以一个特殊的 classification token [CLS] 开始,同时这也会作为分类任务的输出;句子间会以 special seperator token [SEP] 进行分割。
- WordPiece Embedding:n-gram 字符级 Embedding,采用 BPE 双字节编码,可以将单词拆分,比如 “loved” “loving” ”loves“ 会拆分成 “lov”,“ed”,“ing”,“es”。
- Segment Embedding也可以用来分割句子,但主要用来区分句子对。Embedding A 和 Embedding B 分别代表左右句子,如果是普通的句子就直接用 Embedding A。
- Position Embedding 是用来给单词定位的,学习出来的embedding向量。这与Transformer不同,Transformer中是预先设定好的值。
- 80% 的 [MASK] token 会继续保持 [MASK];—my dog is [MASK]
- 10% 的 [MASK] token 会被随机的一个单词取代;my dog is apple
- 10% 的 [MASK] token 会保持原单词不变(但是还是要预测)my dog is hairy
- 在 encoder 的输出上添加一个前馈神经网络,将其转换为词汇的维度
- softmax 计算词汇表中每个单词的概率
- B有一半的几率是A的下一句,即正例;
- B有一半的几率是随机取一个句子作为负例。
- 1. 在分类任务中,例如情感分析等,只需要在 Transformer 的输出之上加一个分类层
- 2. 在QA任务中,问答系统需要接收有关文本序列的 question,并且需要在序列中标记 answer。 可以使用 BERT 学习两个标记 answer 开始和结尾的向量来训练Q&A模型。
- 3. 在命名实体识别(NER)中,系统需要接收文本序列,标记文本中的各种类型的实体(人员,组织,日期等)。 可以用 BERT 将每个 token 的输出向量送到预测 NER 标签的分类层。
- a、b 是 sentence-level 级别的任务,类似句子分类,情感分析等等,输入句子或句子对,在 [CLS] 位置接入 Softmax 输出 Label;
- c是token-level级别的任务,比如 QA 问题,输入问题和段落,在 Paragraph 对应输出的 hidden vector 后接上两个 Softmax 层,分别训练出 Span 的 Start index 和 End index(连续的 Span)作为 Question 的答案;
- d也是token-level级别的任务,比如命名实体识别问题,接上 Softmax 层即可输出具体的分类。
![0](/i/l/?n=23&i=blog/1596082/202304/1596082-20230415232013244-241750493.png)
![0](/i/l/?n=23&i=blog/1596082/202304/1596082-20230415232013360-235324685.png)
![0](/i/l/?n=23&i=blog/1596082/202304/1596082-20230415232013342-489591064.png)
![0](/i/l/?n=23&i=blog/1596082/202304/1596082-20230415232013380-1323627906.png)
![0](/i/l/?n=23&i=blog/1596082/202304/1596082-20230415232013344-1025844452.png)
![0](/i/l/?n=23&i=blog/1596082/202304/1596082-20230415232013427-897657375.png)
- [MASK]标记在实际预测中不会出现,训练时用过多[MASK]影响模型表现;
- 每个batch只有15%的token被预测,所以BERT收敛得比left-to-right模型要慢(它们会预测每个token);
- BERT对硬件资源的消耗巨大。
二、BERT答疑
1、三个Embedding怎么来的 在BERT中,Token,Position,Segment Embeddings 都是通过学习来得到的,pytorch代码中它们是这样的: self.word_embeddings = Embedding(config.vocab_size, config.hidden_size) self.position_embeddings = Embedding(config.max_position_embeddings, config.hidden_size) self.token_type_embeddings = Embedding(config.type_vocab_size, config.hidden_size) BERT 能够处理对输入句子对的分类任务。这类任务就像判断两个文本是否是语义相似的。句子对中的两个句子被简单的拼接在一起后送入到模型中。 那BERT如何去区分一个句子对中的两个句子呢?答案就是segment embeddings.![0](/i/l/?n=23&i=blog/1596082/202304/1596082-20230415231550844-403525679.png)
BERT在第一句前会加一个CLS]标志,最后一层该位对应向量可以作为整句话的语义表示,从而用于下游的分类任务等。与文本中已有的其它词相比,这个无明显语义信息的符号会更“公平”地融合文本中各个词的语义信息,从而更好的表示整句话的语义
5、Self-Attention 的时间复杂度是怎么计算的? O(n^2 d) 相加的 6、Transformer在哪里做了权重共享,为什么可以做权重共享? Transformer在两个地方进行了权重共享: (1)Encoder和Decoder间的Embedding层权重共享; (2)Decoder中Embedding层和FC层权重共享。 解码的词,要有embedding,同时也可作为分类器权重。,Embedding层可以说是通过onehot去取到对应的embedding向量,FC层可以说是相反的,通过向量(定义为 x)去得到它可能是某个词的softmax概率,取概率最大。 FC层的每一行量级相同的前提下,理论上和 x 相同的那一行对应的点积和softmax概率会是最大的(内积)。 通过这样的权重共享可以减少参数的数量,加快收敛。 7、BERT非线性的来源在哪里? 前馈层的gelu激活函数和self-attention,self-attention是非线性的,感谢评论区指出。 8. BERT参数 https://blog.csdn.net/weixin_43922901/article/details/102602557 Bert采用的vocab_size=30522,hidden_size=768,max_position_embeddings=512 LN参数,gamma和beta的维度均为768。因此总参数为768 * 2 + 768 * 2 * 2 * 12(层数) 模型参数Bert模型的版本如下: BERT-Base, Uncased: 12-layer, 768-hidden, 12-heads, 110M parameters BERT-Large, Uncased: 24-layer, 1024-hidden, 16-heads, 340M parameters三、BERT调包和微调
BERT有两个约束条件。- 1. 所有的句子必须被填充或截断成一个固定的长度。
- 2. 最大的句子长度是512个tokens。
![0](/i/l/?n=23&i=blog/1596082/202304/1596082-20230415231550879-1475951028.png)
- 将句子分割成token。
- 添加特殊的[CLS]和[SEP]标记。
- 将这些标记映射到它们的ID上。
- 把所有的句子都垫上或截断成相同的长度。
- 创建注意力Masl,明确区分真实 token 和[PAD]token。
- BertModel
- BertForPreTraining
- BertForMaskedLM
- BertForNextSentencePrediction(下句预测)
- BertForSequenceClassification - 我们将使用的那个。
- BertForTokenClassification
- BertForQuestionAnswering
from transformers import BertForSequenceClassification, AdamW, BertConfig # Load BertForSequenceClassification, the pretrained BERT model with a single # linear classification layer on top. model = BertForSequenceClassification.from_pretrained( "bert-base-uncased", # Use the 12-layer BERT model, with an uncased vocab. num_labels = 2, # The number of output labels--2 for binary classification. # You can increase this for multi-class tasks. output_attentions = False, # Whether the model returns attentions weights. output_hidden_states = False, # Whether the model returns all hidden-states. ) # Tell pytorch to run this model on the GPU. model.cuda()
参考
- 用huggingface.transformers在文本分类任务(单任务和多任务场景下)上微调预训练模型https://blog.csdn.net/PolarisRisingWar/article/details/127365675
- 比赛:Datawhale零基础入门NLP赛事 - Task5 基于深度学习的文本分类https://tianchi.aliyun.com/notebook/118258