Merge pull request #34 from luzixiao/main

Update 2.3-图解BERT.md 👍
This commit is contained in:
erenup 2021-09-23 10:53:23 +08:00 committed by GitHub
commit 37564224ef
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 20 additions and 18 deletions

View File

@ -24,7 +24,7 @@
站在2021年来看2018年是自然语言处理技术的一个转折点运用深度学习技术处理文本的能力通过预训练模型被极大的发挥了出来。同时伴随着NLP开源社区的贡献很多强大的模型被封装成组件让NLP初学者也有机会在各种NLP任务上取得非常好的效果。在众多NLP预训练模型里最经典的基本就是BERT和GPT了因此本文将开始对BERT单篇文章的citation已经接近2万的学习。 站在2021年来看2018年是自然语言处理技术的一个转折点运用深度学习技术处理文本的能力通过预训练模型被极大的发挥了出来。同时伴随着NLP开源社区的贡献很多强大的模型被封装成组件让NLP初学者也有机会在各种NLP任务上取得非常好的效果。在众多NLP预训练模型里最经典的基本就是BERT和GPT了因此本文将开始对BERT单篇文章的citation已经接近2万的学习。
BERT在2018年被提出BERT模型一出现就打破了多个自然语言处理任务的最好记录。BERT的论文发布不久后BERT团队公开了模型的代码并提供了基于大规模新书预训练完成的模型下载。BERT的模型代码和模型参数的开源使得任何一个NLP从业者都可以基于这个强大的模型组件搭建自己的NLP系统也节省了从零开始训练语言处理模型所需要的时间、精力、知识和资源。 BERT在2018年被提出BERT模型一出现就打破了多个自然语言处理任务的最好记录。BERT的论文发布不久后BERT团队公开了模型的代码并提供了基于大规模新书数据集预训练完成的模型下载。BERT的模型代码和模型参数的开源使得任何一个NLP从业者都可以基于这个强大的模型组件搭建自己的NLP系统也节省了从零开始训练语言处理模型所需要的时间、精力、知识和资源。
那么BERT具体干了一件什么事情呢如下图所示BERT首先在大规模无监督语料上进行预训练然后在预训练好的参数基础上增加一个与任务相关的神经网络层并在该任务的数据上进行微调训最终取得很好的效果。BERT的这个训练过程可以简述为预训练+微调finetune已经成为最近几年最流行的NLP解决方案的范式。 那么BERT具体干了一件什么事情呢如下图所示BERT首先在大规模无监督语料上进行预训练然后在预训练好的参数基础上增加一个与任务相关的神经网络层并在该任务的数据上进行微调训最终取得很好的效果。BERT的这个训练过程可以简述为预训练+微调finetune已经成为最近几年最流行的NLP解决方案的范式。
@ -35,13 +35,15 @@ BERT在2018年被提出BERT模型一出现就打破了多个自然语言处
- 下载在无监督语料上预训练好的BERT模型一般来说对应了3个文件BERT模型配置文件用来确定Transformer的层数隐藏层大小等BERT模型参数BERT词表BERT所能处理的所有token - 下载在无监督语料上预训练好的BERT模型一般来说对应了3个文件BERT模型配置文件用来确定Transformer的层数隐藏层大小等BERT模型参数BERT词表BERT所能处理的所有token
- 针对特定任务需要在BERT模型上增加一个任务相关的神经网络比如一个简单的分类器然后在特定任务监督数据上进行微调训练。微调的一种理解学习率较小训练epoch数量较少对模型整体参数进行轻微调整 - 针对特定任务需要在BERT模型上增加一个任务相关的神经网络比如一个简单的分类器然后在特定任务监督数据上进行微调训练。微调的一种理解学习率较小训练epoch数量较少对模型整体参数进行轻微调整
先来看一下如何使用BERT进行句子分类 先来看一下如何使用BERT进行句子分类
假设我们的句子分类任务是判断一个邮件是“垃圾邮件”或者“非垃圾邮件”如下图所示。当然除了垃圾邮件判断也可以是其他NLP任务比如 假设我们的句子分类任务是判断一个邮件是“垃圾邮件”或者“非垃圾邮件”如下图所示。当然除了垃圾邮件判断也可以是其他NLP任务比如
- 输入:电影或者产品的评价。输出:判断这个评价是正面的还是负面的。 - 输入:电影或者产品的评价。输出:判断这个评价是正面的还是负面的。
- 输入:两句话。输出:两句话是否是同一个意思。 - 输入:两句话。输出:两句话是否是同一个意思。
![垃圾邮件分类](./pictures/3-trash.png)图:垃圾邮件分类 ![垃圾邮件分类](./pictures/3-trash.png)
图:垃圾邮件分类
如下图所示为了能够使用BERT进行句子分类我们在BERT模型上增加一个简单的classifier层由于这一层神经网络参数是新添加的一开始只能随机初始化它的参数所以需要用对应的监督数据来训练这个classifier。由于classifier是连接在BERT模型之上的训练的时候也可以更新BERT的参数。 如下图所示为了能够使用BERT进行句子分类我们在BERT模型上增加一个简单的classifier层由于这一层神经网络参数是新添加的一开始只能随机初始化它的参数所以需要用对应的监督数据来训练这个classifier。由于classifier是连接在BERT模型之上的训练的时候也可以更新BERT的参数。
@ -60,13 +62,13 @@ BERT在2018年被提出BERT模型一出现就打破了多个自然语言处
## 模型输入 ## 模型输入
接着看一下模型的输入和输出BERT模型输入有一点特殊的地方是在一句话最开始拼接了一个[CLS] token如下图所示。这个特殊的[CLS] token经过BERT得到的向量表示通常被用作当前的句子表示。除了这个特殊的[CLS] token其余输入的单词类似篇章2.2的Transformer。BERT将一串单词作为输入这些单词多层encoder中不断向上流动每一层都会经过 Self-Attention和前馈神经网络。 接着看一下模型的输入和输出BERT模型输入有一点特殊的地方是在一句话最开始拼接了一个[CLS] token如下图所示。这个特殊的[CLS] token经过BERT得到的向量表示通常被用作当前的句子表示。除了这个特殊的[CLS] token其余输入的单词类似篇章2.2的Transformer。BERT将一串单词作为输入这些单词多层encoder中不断向上流动每一层都会经过 Self-Attention和前馈神经网络。
![模型输入](./pictures/3-bert-input.png)图:模型输入 ![模型输入](./pictures/3-bert-input.png)图:模型输入
## 模型输出 ## 模型输出
BERT输入的所有token经过BERt编码后,会在每个位置输出一个大小为 hidden_size在 BERT-base中是 768的向量。 BERT输入的所有token经过BERT编码后,会在每个位置输出一个大小为 hidden_size在 BERT-base中是 768的向量。
![BERT output](./pictures/3-bert-output.png)图BERT output ![BERT output](./pictures/3-bert-output.png)图BERT output
@ -78,17 +80,17 @@ BERT输入的所有token经过BERt编码后会在每个位置输出一个大
## 预训练任务Masked Language Model ## 预训练任务Masked Language Model
知道了模型输入、输出、Transformer结构那么BERT是如何无监督进行训练的呢如何得到有效的词、句子表示信息呢以往的NLP预训练通常是基于语言模型进行比如给定语言模型的前3个词让模型预测第4个词。但是BERT是基于Masked language model进行预训练的将输入文本序列的部分15%单词随机Mask掉让BERT来预测这些被Mask的词语。如下图所示 知道了模型输入、输出、Transformer结构那么BERT是如何无监督进行训练的呢如何得到有效的词、句子表示信息呢以往的NLP预训练通常是基于语言模型进行比如给定语言模型的前3个词让模型预测第4个词。但是BERT是基于Masked language model进行预训练的将输入文本序列的部分15%单词随机Mask掉让BERT来预测这些被Mask的词语。如下图所示
![BERT mask](./pictures/3-bert-mask.webp)图: BERT mask ![BERT mask](./pictures/3-bert-mask.webp)图: BERT mask
这种训练方式最早可以追溯到Word2vec时代典型的Word2vec算法便是基于词C两边的A、B和D、E词来预测出词C。 这种训练方式最早可以追溯到Word2Vec时代典型的Word2Vec算法便是基于词C两边的A、B和D、E词来预测出词C。
## 预训练任务:相邻句子判断 ## 预训练任务:相邻句子判断
除了masked language modelBERt在预训练时还引入了一个新的任务判断两个句子是否是相邻句子。如下图所示输入是sentence A和sentence B经过BERT编码之后使用CLS token的向量表示来预测两个句子是否是相邻句子。 除了masked language modelBERT在预训练时还引入了一个新的任务判断两个句子是否是相邻句子。如下图所示输入是sentence A和sentence B经过BERT编码之后使用[CLS] token的向量表示来预测两个句子是否是相邻句子。
![2个句子任务](./pictures/3-bert-2sent.webp)图: 2个句子任务 ![2个句子任务](./pictures/3-bert-2sent.webp)图: 2个句子任务
注意事项为了本文的描述方便在前面的叙述中均省略了BERT tokenize的过程但读者朋友需要注意BERT实际上使用的是WordPieces作为最小的处理单元采用的是wordpiece算法分词token而不是使用单词本身。在 WordPiece中有些词会被拆分成更小的部分。关于WordPiece分词本文不过多展开感兴趣的读者可以阅读和学习[subword tokenizer](https://towardsdatascience.com/a-comprehensive-guide-to-subword-tokenisers-4bbd3bad9a7c)。另外,判断两个句子是否相邻这个任务后来的研究中逐渐被淡化了比如roberta模型在被提出的时候就不再使用该任务进行预训练了。 注意事项为了本文的描述方便在前面的叙述中均省略了BERT tokenize的过程但读者朋友需要注意BERT实际上使用的是WordPieces作为最小的处理单元采用的是wordpiece算法分词token而不是使用单词本身。在 WordPiece中有些词会被拆分成更小的部分。关于WordPiece分词本文不过多展开感兴趣的读者可以阅读和学习[subword tokenizer](https://towardsdatascience.com/a-comprehensive-guide-to-subword-tokenisers-4bbd3bad9a7c)。另外,判断两个句子是否相邻这个任务后来的研究中逐渐被淡化了比如roberta模型在被提出的时候就不再使用该任务进行预训练了。
## BERT的应用 ## BERT的应用
@ -100,7 +102,7 @@ BERT论文展示了BERT在多种任务上的应用如下图所示。可以用
## BERT特征提取 ## BERT特征提取
由于BERT模型可以得到输入序列所对应的所有token的向量表示因此不仅可以使用最后一BERT的输出连接上任务网络进行微调还可以直接使用这些token的向量当作特征。比如可以直接提取每一层encoder的token表示当作特征输入现有的特定任务神经网络中进行训练。 由于BERT模型可以得到输入序列所对应的所有token的向量表示因此不仅可以使用最后一BERT的输出连接上任务网络进行微调还可以直接使用这些token的向量当作特征。比如可以直接提取每一层encoder的token表示当作特征输入现有的特定任务神经网络中进行训练。
![BERT特征提取](./pictures/3-bert-feature.png)图: BERT特征提取 ![BERT特征提取](./pictures/3-bert-feature.png)图: BERT特征提取
@ -138,15 +140,15 @@ BERT论文展示了BERT在多种任务上的应用如下图所示。可以用
#### 语境问题 #### 语境问题
如果我们使用 Glove 的词嵌入表示方法,那么不管上下文是什么,单词 "stick" 都只表示为一个向量。一些研究人员指出,像 "stick" 这样的词有多种含义。为什么不能根据它使用的上下文来学习对应的词嵌入呢这样既能捕捉单词的语义信息又能捕捉上下文的语义信息。于是语境化的词嵌入模型应运而生ELMO 如果我们使用 Glove 的词嵌入表示方法,那么不管上下文是什么,单词 "stick" 都只表示为一个向量。一些研究人员指出,像 "stick" 这样的词有多种含义。为什么不能根据它使用的上下文来学习对应的词嵌入呢这样既能捕捉单词的语义信息又能捕捉上下文的语义信息。于是语境化的词嵌入模型应运而生ELMo
![ELMO](./pictures/3-elmo.webp)图ELMO ![ELMO](./pictures/3-elmo.webp)图ELMo
语境化的词嵌入,可以根据单词在句子语境中的含义,赋予不同的词嵌入。 语境化的词嵌入,可以根据单词在句子语境中的含义,赋予不同的词嵌入。
ELMo没有对每个单词使用固定的词嵌入而是在为每个词分配词嵌入之前查看整个句子融合上下文信息。它使用在特定任务上经过训练的双向LSTM来创建这些词嵌入。 ELMo没有对每个单词使用固定的词嵌入而是在为每个词分配词嵌入之前查看整个句子融合上下文信息。它使用在特定任务上经过训练的双向LSTM来创建这些词嵌入。
![ELMO embedding](./pictures/3-elmo-emb.png)图: ELMO embedding ![ELMO embedding](./pictures/3-elmo-emb.png)图: ELMo embedding
ELMo 在语境化的预训练这条道路上迈出了重要的一步。ELMo LSTM 会在一个大规模的数据集上进行训练,然后我们可以将它作为其他语言处理模型的一个部分,来处理自然语言任务。 ELMo 在语境化的预训练这条道路上迈出了重要的一步。ELMo LSTM 会在一个大规模的数据集上进行训练,然后我们可以将它作为其他语言处理模型的一个部分,来处理自然语言任务。
@ -155,15 +157,15 @@ ELMo 在语境化的预训练这条道路上迈出了重要的一步。ELMo LSTM
ELMo 通过训练,预测单词序列中的下一个词,从而获得了语言理解能力,这项任务被称为语言建模。要实现 ELMo 很方便,因为我们有大量文本数据,模型可以从这些数据中学习,而不需要额外的标签。 ELMo 通过训练,预测单词序列中的下一个词,从而获得了语言理解能力,这项任务被称为语言建模。要实现 ELMo 很方便,因为我们有大量文本数据,模型可以从这些数据中学习,而不需要额外的标签。
![ELMO 训练](./pictures/3-elmo-pre.webp)图: ELMO 训练 ![ELMO 训练](./pictures/3-elmo-pre.webp)图: ELMo 训练
ELMo预训练过程是一个典型的语言模型以 "Lets stick to" 作为输入,预测下一个最有可能的单词。当我们在大规模数据集上训练时,模型开始学习语言的模式。例如,在 "hang" 这样的词之后,模型将会赋予 "out" 更高的概率(因为 "hang out" 是一个词组),而不是输出 "camera"。 ELMo预训练过程是一个典型的语言模型以 "Lets stick to" 作为输入,预测下一个最有可能的单词。当我们在大规模数据集上训练时,模型开始学习语言的模式。例如,在 "hang" 这样的词之后,模型将会赋予 "out" 更高的概率(因为 "hang out" 是一个词组),而不是输出 "camera"。
在上图中,我们可以看到 ELMo 头部上方展示了 LSTM 的每一步的隐藏层状态向量。在这个预训练过程完成后,这些隐藏层状态在词嵌入过程中派上用场。 在上图中,我们可以看到 ELMo 头部上方展示了 LSTM 的每一步的隐藏层状态向量。在这个预训练过程完成后,这些隐藏层状态在词嵌入过程中派上用场。
![ELMO 训练 stick](./pictures/3-elmo-pre1.png)图ELMO 训练 ![ELMO 训练 stick](./pictures/3-elmo-pre1.png)图ELMo 训练
ELMo 通过将LSTM模型的隐藏表示向量(以及初始化的词嵌入)以某种方式(向量拼接之后加权求和)结合在一起,实现了带有语境化的词嵌入。 ELMo 通过将LSTM模型的隐藏表示向量(以及初始化的词嵌入)以某种方式(向量拼接之后加权求和)结合在一起,实现了带有语境化的词嵌入。
![ELMO 训练 stick](./pictures/3-elmo-pre2.webp)图ELMO 训练 ![ELMO 训练 stick](./pictures/3-elmo-pre2.webp)图ELMO 训练
@ -171,7 +173,7 @@ ELMo 通过将LSTM模型的隐藏成表示向量以及初始化的词嵌入
随着Transformer论文和代码的发布以及它在机器翻译等任务上取得的成果开始让人们认为它是LSTM的替代品。一部分原因是1. 因为 Transformer 可以比 LSTM 更好地处理长期依赖2. Transformer可以对输入进行并行运算。 随着Transformer论文和代码的发布以及它在机器翻译等任务上取得的成果开始让人们认为它是LSTM的替代品。一部分原因是1. 因为 Transformer 可以比 LSTM 更好地处理长期依赖2. Transformer可以对输入进行并行运算。
2017年基于Transformer的Encoder-Decode展示了它在机器翻译上的威力。但怎么才能用它来做文本分类呢你怎么才能使用它来预训练一个语言模型并能够在其他任务上进行微调下游任务是指那些能够利用预训练模型的监督学习任务 2017年基于Transformer的Encoder-Decoder展示了它在机器翻译上的威力。但怎么才能用它来做文本分类呢?你怎么才能使用它来预训练一个语言模型,并能够在其他任务上进行微调(下游任务是指那些能够利用预训练模型的监督学习任务)?
#### OpenAI Transformer预训练一个Transformer Decoder进行语言建模 #### OpenAI Transformer预训练一个Transformer Decoder进行语言建模
@ -189,7 +191,7 @@ ELMo 通过将LSTM模型的隐藏成表示向量以及初始化的词嵌入
#### BERTDecoder到Encoder #### BERTDecoder到Encoder
OpenAI Transformer为我们提供了一个基于Transformer的预训练网络。但是在把LSTM换成Transformer 的过程中有些东西丢失了。比如之前的ELMo的语言模型是双向的但 OpenAI Transformer 只训练了一个前向的语言模型。我们是否可以构建一个基于 Transformer 的语言模型,它既向前看,又向后看(用技术术语来说 - 融合上文和下文的信息)。那答案就是BERT基于双向Transformer的encoder在Masked language model上进行预训练最终在多项NLP下游任务取得了SOTA效果。 OpenAI Transformer为我们提供了一个基于Transformer的预训练网络。但是在把LSTM换成Transformer 的过程中有些东西丢失了。比如之前的ELMo的语言模型是双向的但 OpenAI Transformer 只训练了一个前向的语言模型。我们是否可以构建一个基于 Transformer 的语言模型,它既向前看,又向后看(用技术术语来说 - 融合上文和下文的信息)答案就是BERT基于双向Transformer的encoder在Masked language model上进行预训练最终在多项NLP下游任务取得了SOTA效果。
## 致谢 ## 致谢
主要由哈尔滨工业大学张贤同学翻译经过原作者授权撰写由多多重新组织和整理。感谢Jacob Devlin、Matt Gardner、Kenton Lee、Mark Neumann 和 [Matthew Peters](https://twitter.com/mattthemathman) 为这篇文章的早期版本提供了反馈。 主要由哈尔滨工业大学张贤同学翻译经过原作者授权撰写由多多重新组织和整理。感谢Jacob Devlin、Matt Gardner、Kenton Lee、Mark Neumann 和 [Matthew Peters](https://twitter.com/mattthemathman) 为这篇文章的早期版本提供了反馈。