从0开始学bert

1. bert模型架构

基础架构——transformer的encoder部分(如下图)

transformer 是多层encoder-多层decoder结构。input = word_embedding + positional_encoding(word_embedding 词向量,可以是随机初始化,也可以使用 word2vec;positional_embedding用正余弦表示位置特征)

而bert是多层encoder 结构。

1. 输入部分

input = token_embedding + segment_embedding + positional_embedding

token_embedding ——词向量,可以是随机初始化,也可以使用 word2vec

segment_embedding  ——用于对两个句子进行区分,CLS到到中间SEP,全部都是E_A(整个句子都是一样的),也可以全部用0;SEP到SEP,全部用E_B,全部用1.

positional_embedding ——区别于transformer中的 positional_encoding,使用随机初始化(但为什么用随机初始化,而不用正余弦函数,没有找到很好地解释)

input 中的特殊字符:CLS,SEP

(bert有两个训练任务,一个是NSP,next sentence prediction,用来判断两个句子之间的关系,因此,需要有一个字符告诉计算机句子与句子之间的分割,所以有了SEP字符。同时,NSP也是句子之间的二分类任务,因此,作者在句子前接了一个CLS字符,训练的时候,将CLS输出后面接一个二分类器,这就是CLS的作用。但是,有一个问题,很多人认为CLS代表整个句子的语义信息,但是原文并没有这种说法,所以可以作为一个思考点。B站UP主做过一个测试,他也提供了一些其他证据,bert预训练模型直接拿来做sentence embedding,效果甚至不如word embedding,CLS效果最差。

2. 多头注意力部分

3. 前馈神经网络

区分:encoder与 decoder

transformer结构


2. 如何做预训练

2.1 MLM 掩码语言模型

bert使用大量无监督预料进行预训练。无监督模型有两种目标函数,比较受重视:

举例:原始预料“我爱吃饭

1. AR(auto-regressive 自回归模型):只考虑单侧信息,典型的GPT

P(我爱吃饭) =P(我)P(爱|我)P(吃|我爱)P(饭|我爱吃)

AR的优化目标是:“我爱吃饭”的概率 = “”出现的概率 \times ”出现的条件下,“” 出现的概率\times ...

这个优化目标,是有一个前后依赖关系的。所以说,AR只用到了单侧信息

2. AE(auto-encoding 自编码模型):从损坏的输入数据中预测重建原始数据,可以使用上下文信息

对句子进行 mask,原句编程 “我爱mask饭

P(我爱吃饭|我爱mask饭)=P(mask=吃|我爱饭)

AE的优化目标:“我爱吃饭”的概率 = “我爱饭”出现的条件下,mask=吃的概率

本质:打破文本原有的信息,让模型训练的时候,进行文本重建

模型缺点:

P(我爱吃饭|我爱mask mask)=P(吃|我爱)P(饭|我爱)

mask之后, 之间被看做是独立的,但是本身是有关系的。

mask策略:

随机mask 15%的单词,这 15%中,0.1被替换成其他单词(有可能选到这个单词本身),0.1原封不动,0.8替换成其他(这个比例问题没有知道到解释),如下图:

2.2 NSP

NSP样本如下:

1. 从训练语料库汇总取出两个连续的段落作为正样本(说明两个段落来自于同一个文档,同一个主题,且顺序没有颠倒

2. 从不同文档中随机创建一对段落作为负样本(不同的主题)

缺点:主题预测 连贯性预测 合并为一个单项任务

3. 如何微调bert,提升下游任务中的效果

四个常见的下游任务:

a. 句子对分类任务——本质是文本匹配,把两个句子拼接起来,判断是否相似。CLS接二分类器,输出 0-相似,1-不相似

b. 单个句子分类任务——CLS输出,接一个分类器,进行分类

c. 问答任务

d. 序列标注任务——把所有的token 输出,然后接softmax,进行标注(比如词性标注,命名实体识别)

如何提升bert下游任务表现?即微调策略。

基本步骤:1-获取一个训练好的bert,比如谷歌中文BERT;2-基于任务数据进行微调。

比如,做微博情感分析:

1-获取通用的预训练模型,比如谷歌中文BERT

2-在相同领域上继续做模型训练,比如在微博文本上进行训练(Domain tansfer 领域自适应,或 领域迁移)

3-在任务相关的小数据上继续训练,在微博情感任务文本上进行训练(task transfer 任务自适应,或 任务迁移)

4-在任务相关数据上做具体的任务 (fine-tune 微调

在上面 领域迁移 步骤中,还可以进行 further pre-traning,比如:

1-动态mask:每次epoch去训练的时候mask

2-n-gram mask:ERNIE 和 SpanBERT类似于做了实体词 的 mask

可以对参数进行优化,从而提升模型效果:

batch size:16,32---128,影响不大,主要看及其效果

learning rate(Adam):5e-5, 3e-5, 2e-5 尽可能小一点,避免灾难性遗忘

number of epochs: 3,4

weighted decay:修改后的Adam,使用warmup, 搭配线性衰减

其他:

数据增强、自蒸馏、外部知识融入

比如 ERNIE ,融入了知识图谱,加入了实体信息

4. 如何在脱敏数据中心使用BERT等预训练模型

如果本身语料很大,可以从0开始训练一个bert

否则,按照词频,把脱敏数字对找到中文(假如是中文语料),使用中文做bert初始化,然后基于新的中文语料训练bert

5. 代码解读

代码最核心的一点,MLM损失函数的计算:

15%的词汇被mask,8:1:1的比例进行了不同的处理,那么损失函数究竟计算的是哪一部分?

最下面一行 是原始字符对应的索引。

mask:把第三个字符 从索引 13 替换成了 4 对应的字符。

接下来,经过三个embedding,然后拼接,组合成input

然后,经过 encoder 层(N层)

得到每个token的embedding:

第一个对应的是 CLS,可以接linear层,做二分类任务

被mask的位置,接linear层,在 词表大小的维度(bert的此表大小是22128)接 softmax,挑选最有可能的词汇,做损失函数

1. 参数部分

模型参数

maxlen- 如果是document类很长的文本,一般会使用一些策略,使最大长度控制在256以内。

max_pred -为了限制一个句子最大可以预测多少个token

n_layers - 选择多少个 encoder,base一般选12,large一般选24

n_head - 多少个头(多头注意力机制)

d_ff -前馈神经网络的维度,不用特意写成768*4,没什么意义,直接写成3072

d_q = d_v Q-K-V向量的维度,一般K和V要一致

n_segments NSP做二分类任务,有两个SEP(区分出两个segments)

数据预处理

text 是 输入样本,正常任务中肯定是从文本文件中读取

sentences 是数据预处理的代码,去除掉原始文本中一些没用的字符

加下来,创建一个词表,其中 【PAD】编码为0、【CLS】-1、【SEP】-2、【MASK】-3等特殊字符进行编码,而文本中的字符,从3以后取。

token_list 是把文本转化成数字

预训练任务的数据构建部分-1
预训练任务的数据构建部分-2
code 对应的操作

为什么补0?

补0的原因在于这个损失函数,补0的位置不参与计算
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 1.BERT整体模型架构 基础架构 - TRM的Encoder部分image.pngBERT的基础架构是trans...
    许志辉Albert阅读 1,857评论 0 3
  • BERT 模型是 Google 在 2018 年提出的一种 NLP 模型,成为最近几年 NLP 领域最具有突破性的...
    NLP与人工智能阅读 24,314评论 2 10
  • 本文是对bert的细节进行整理,分成3个部分的问题: 目录 输入 与transformer相比输入有什么不同? b...
    张虾米试错阅读 8,078评论 3 3
  • transformers是huggingface提供的预训练模型库,可以轻松调用API来得到你的词向量。trans...
    晓柒NLP与药物设计阅读 8,250评论 0 10
  • 深度学习在NLP领域的发展 一、词向量历史 1.1 第一阶段: Word embeddignd Word 2Vec...
    骆旺达阅读 2,755评论 0 7