【NLP】 一步步理解BERT

一步步理解BERT

csdn:https://blog.csdn.net/qq_36645271html

github:https://github.com/aimi-cn/AILearnersgit

本文转载自CSDN做者财神Childe ,在此对原做者的分享表示感谢!github

NLP

NLP:天然语言处理(NLP)是信息时代最重要的技术之一。理解复杂的语言也是人工智能的重要组成部分。而自google在2018年10月底公布BERT在11项nlp任务中的卓越表后,BERT(Bidirectional Encoder Representation from Transformers)就成为NLP一枝独秀,本文将为你们层层剖析bert。
NLP常见的任务主要有: 中文自动分词、句法分析、自动摘要、问答系统、文本分类、指代消解、情感分析等。web

咱们会从one-hot、word embedding、rnn、seq2seq、transformer一步步逼近bert,这些是咱们理解bert的基础。网络

Word Embedding

首先咱们须要对文本进行编码,使之成为计算机能够读懂的语言,在编码时,咱们指望句子之间保持词语间的类似行,词的向量表示是进行机器学习和深度学习的基础。
word embedding的一个基本思路就是,咱们把一个词映射到语义空间的一个点,把一个词映射到低维的稠密空间,这样的映射使得语义上比较类似的词,他在语义空间的距离也比较近,若是两个词的关系不是很接近,那么在语义空间中向量也会比较远。
在这里插入图片描述
如上图英语和西班牙语映射到语义空间,语义相同的数字他们在语义空间分布的位置是相同的架构

在句子的空间结构上咱们指望获取更底层的之间的关系好比:-app

  • V K i n g V Q u e e n = V M a n V W o m e n V_{King} - V_{Queen} = V_{Man}-V_{Women}
  • V P a r i s V F r a n c e = V B e r l i n V G e r m a n V_{Paris} - V_{France} = V_{Berlin} -V_{German}

king和queen之间的关系相比与man与woman的关系大致应该相同的,那么他们经过矩阵运算,维持住这种关系框架

Paris 和France之间的关系相比与Berlin与German的关系大致应该相同的,那么他们经过矩阵运算,维持住这种关系机器学习

简单回顾一下word embedding,对于nlp来讲,咱们输入的是一个个离散的符号,对于神经网络来讲,它处理的都是向量或者矩阵。因此第一步,咱们须要把一个词编码成向量。最简单的就是one-hot的表示方法。以下图所示:
在这里插入图片描述
one-hot encoding编码
一般咱们有不少的词,那只在出现的位置显示会,那么势必会存在一些问题:分布式

  1. 高维的表示
  2. 稀疏性
  3. 正交性(任意两个词的距离都是1,除了本身和本身,这样就带来一个问题,猫和狗距离是1,猫和石头距离也是1,但咱们理解上猫和狗距离应该更近一些)

两个词语义上没法正确表示,咱们更但愿低维的类似的比较接近,语义相近的词距离比较近,语义不想近的词,距离也比较远。
解决的办法就是word enbedding,是一种维位稠密的表示。

Neural Network Language Model(神经网络语言模型)

咱们都知道word2vec,glove。其实更早以前的神经网络语言模型里出现。已经有比较早的一个词向量了。语言模型是nlp的一个基本任务,是给定一个句子w,包括k个词,咱们须要计算这个句子的几率。使用分解成条件几率乘积的形式。变成条件几率的计算。

传统的方法,统计的n-gram的,词频统计的形式,出现的多,几率就高,出现少几率就低。

  • 不能常时依赖上下文,如:他出生在法国,他能够讲一口流利的( __ ),咱们但愿法语的几率比英语、汉语的几率要高。n-gram记住只能前面有限几个词,若参数比较多,它根本学不到这复杂关系,这是传统语言模型比较大的一个问题。这个能够经过后面的rnn、lstm解决,咱们这里先不讨论。
  • 第二个问题就是泛化能力的问题,泛化能力,或者说不能共享上下文的信息,我要去( __ )玩, 北京、上海应该是同样的,由于都是中国的一个城市,几率应该相等或相近的,可是由于预料中北京不少,因此出现上海的几率很低。那神经网络语言模型就能够解决这样的问题。
    在这里插入图片描述
    神经网络语言模型架构如上图:

将每一个词向量拼接成句子矩阵。每一列都是一个词, 如北京、上海、 天津比较近,大体相同一块区域,因此当预测时,能够给出大概相同的几率,不只仅与预料中统计结果有关系。矩阵相乘就能够提取出这个词,可是为了提取一个词,咱们要进行一次矩阵运算,这个比较低效,因此比较成熟的框架都提供了查表的方法,他的效率更高。

由于上下文环境很类似,会共享相似的context,在问我要去 ( __ )几率会比较大。这也是神经网络语言模型的一个好处。咱们经过神经网络语言模型获得一个词向量。固然咱们也能够用其余的任务来作,同样获得词向量,好比句法分析,可是那些任务大部分是有监督的学习,须要大量的标注信息。

语言模型是非监督的,资料获取不须要很大的成本。

word2vec和神经网络语言模型不一样,直接来学习这个词向量,使用的基本假设是分布式假设,若是两个词的上下文时类似的,那么他们语义也是类似的。
在这里插入图片描述
word2vec分为cbow(根据context预测中心词)和skip-gram(根据中心词预测context)两种。
在这里插入图片描述
咱们能够经过word2vec或者 glove这种模型在大量的未标注的语料上学习,咱们能够学习到比较好的向量表示,能够学习到词语之间的一些关系。好比男性和女性的关系距离,时态的关系,学到这种关系以后咱们就能够把它做为特征用于后续的任务,从而提升模型的泛化能力。

可是同时存在一些问题好比:

  • He deposited his money in this bank .
  • His soldiers were arrayed along the river bank .

word embeding 有个问题就是咱们的词一般有不少语义的,好比bank是银行仍是河岸,具体的意思要取决与上下文,若是咱们强行用一个向量来表示语义的话,只能把这两种语义都编码在这个向量里,但实际一个句子中,一个词只有一个语义,那么这种编码是有问题的。

RNN/LSTM/GRU

那么这种上下文的语义能够经过RNN/LSTM/GRU来解决,RNN与普通深度学习不一样的是,RNN是一种序列的模型,会有必定的记忆单元,可以记住以前的历史信息,从而能够建模这种上下文相关的一些语义。RNN中的记忆单元能够记住当前词以前的信息。
在这里插入图片描述
RR能够解决,理论上咱们但愿学到很长的关系,可是因为梯度消失的问题,因此长时依赖不能很好的训练。
在这里插入图片描述
其实lstm能够解决RNN长时依赖梯度消失的问题。

seq2seq

对于翻译,咱们不可能要求英语第一个词必定对应法语的第一个词,不能要求长度同样,对于这样一个rnn不能解决这一问题。咱们使用两个rnn拼接成seq2seq来解决。

  1. 咱们能够用两段RNN组成seq2seq模型
  2. 从而能够来作翻译,摘要、问答和对话系统。

好比经典的翻译例子法语到英语的翻译,由encoder编码到语义空间和decoder根据语义空间解码翻译成一个个的英语句子。
在这里插入图片描述
encoder把要翻译的句子,映射到了整个语义空间,decoder根据语义空间再逐一翻译出来,可是句子长度有时会截断。有一个问题,咱们须要一个固定长度的context向量来编码全部语义,这个是很困难的,要记住每个细节是不可能的。用一个向量记住整个语义是很困难的。
在这里插入图片描述
这时候咱们引入了attention机制。
在这里插入图片描述
能够理解为context只记住了一个大概的提取信息,一种方法是作内积,内积大就关注大,这里能够理解为一种提取的方式,当提取到相关内容,再与具体的ecoder位置计算,获得更精细的内容。
pay attention 作内积。越大越相近 约重要,后续的attention、transformer都是对seq2seq的一个改进,经过这种能够解决word embbeing没有上下文的一个问题。

加上attention机制,咱们就取得了很大的成绩,可是仍然存在一个问题,顺序依赖,以下图:t依赖t-1,t-1依赖t-2,串行的,很难并行的计算,持续的依赖的关系,一般很慢,没法并行:
在这里插入图片描述

  • The animal didn’t cross the street because it was too tired.
  • The animal didn’t cross the street because it was too narrow.

存在单向信息流的问题,只看前文,咱们很难猜想it指代的具体内容,编码的时候咱们要看整个句子的上下文,只看前面或者只看后面是不行的。RNN的两个问题:

  1. 顺序依赖,t依赖t-1时刻。
  2. 单向信息流(如例子中指代信息,不能肯定)
  3. 须要一些比较多的监督数据,对于数据获取成本很高的任务,就比较困难,在实际中很难学到复杂的上下文关系

Contextual Word Embedding

要解决RNN的问题,就引入了contextual word embedding。

contextual word embedding:无监督的上下文的表示,这种无监督的学习是考虑上下文的,好比ELMo、OpenAI GPT、BERT都是上下文相关的词的表示方法。

attention是须要两个句子的,咱们不少时候只有一个句子,这就须要self-attention。提取信息的时候、编码时self-atenntion是自驱动的,self-attention关注的词的先后整个上下文。
在这里插入图片描述
self-attention最先是transformer的一部分。transformer是怎么解决这一问题的?

transformer

本质也是一个encoder与decoder的过程,最起初时6个encoder与6个decoder堆叠起来,若是是LSTM的话,一般很难训练的很深,不能很好的并行。
在这里插入图片描述
每一层结构都是相同的,咱们拿出一层进行解析,每一层有self-attention和feed-forward,decoder还有普通的attention输入来自encoder,和seq-2seq同样,我在翻译某一个词的时候会考虑到encoder的输出,来作一个普通的attention。
在这里插入图片描述
以下图例子给定两个词 thinking和machies,首先经过word embedding把它变成向量,经过self-attention,把它变成一个向量,这里的sefl-attention时考虑上下文的。而后再接全链接层,计算 z 1 z_1 的时候我要依赖 x 1 x 2 x 3 x_1 、x_2 、x_3 整个序列的,才能算 z 1 z 2 z_1,z_2 也同样,我算 r 1 r_1 的时候时不须要 z 2 z_2 的,只要有 z 1 z_1 我就能够算 r 1 r_1 。只要有 z 2 z_2 就能算 r 2 r_2 ,这个是比较大的一个区别,这样就能够并行计算。
在这里插入图片描述
咱们来看看self-attention具体是怎么计算的:
在这里插入图片描述
假设只有两个词,映射成长度只有四的向量,接下来使用三个变换矩阵 w q w k w v w_q w_k w_v ,分别把每一个向量变换成三个向量 q 1 k 1 v 1 q 2 k 2 v 2 q_1 k_1 v_1 q_2 k_2 v_2 这里是与设映的向量相乘获得的。
在这里插入图片描述
获得向量以后就能够进行编码了,考虑上下文,如上文提到的bank同时有多个语义,编码这个词的时候要考虑到其余的词,具体的计算是 q 1 k 1 q_1 k_1 作内积 q 2 k 2 q_2 k_2 作内积获得score,内积越大,表示约类似,softmax进行变成几率。花0.88的几率注意Thinking,0.12注意macheins这个词:
在这里插入图片描述
这样就能够计算 z 1 z_1 了, z 1 = 0.88 v 1 + 0.12 z 2 z_1=0.88v_1+0.12z_2 z 2 z_2 的计算也是相似的:
在这里插入图片描述
q表示为了编码本身去查询其余的词,k表示被查询,v表示这个词的真正语义,通过变换就变成真正的包含上下文的信息,普通attention能够理解为self-attention的一个特例,与普通attention的对比:
在这里插入图片描述
实际中是多个head, 即多个attention(多组qkv),经过训练学习出来的。不一样attention关注不一样的信息,指代消解 上下位关系,多个head,原始论文中有8个,每一个attention获得一个三维的矩阵
在这里插入图片描述
在这里插入图片描述
将8个3维的拼成24维,信息太多 通过24 *4进行压缩成4维。
在这里插入图片描述
位置编码:

  • 北京 到 上海 的机票
  • 上海 到 北京 的机票

self-attention是不考虑位置关系的,两个句子中北京,初始映射是同样的,因为上下文同样,qkv也是同样的,最终获得的向量也是同样的。这样一个句子中调换位置,其实attention的向量是同样的。实际是不同的,一个是出发城市,一个是到达城市。
在这里插入图片描述
引入位置编码,绝对位置编码,每一个位置一个 Embedding,每一个位置一个embedding,一样句子,多了个词 就又不同了,编码就又不同了。

  • 北京到上海的机票 vs 你好,我要北京到上海的机票

tranformer原始论文使用相对位置编码,后面的bert open gpt使用的是简单绝对位置编码:
在这里插入图片描述
你们能够尝试bert换一下相对位置会不会更好:transformer中encoder的完整结构,加上了残差链接和layerNorm。
在这里插入图片描述
decoder加上了普通的attention,最后一刻的输出,会输入
在这里插入图片描述
transformer的decoder不能利用未知的信息,即单向信息流问题。

transformer 解决的问题:

能够并行计算,训练的很深,到后来的open gpt能够到12层 bert的1六、24层。

单向信息流的问题:至少在encoder的时候考虑前面和后面的信息,因此能够取得很好的效果,
transformer解决了普通word embedding 没有上下文的问题,可是解决这个问题,须要大量的标注信息样本。

如何解决transformer的问题,就引入了elmo。

elmo:无监督的考虑上下文的学习。
在这里插入图片描述
一个个的预测的语言模型:
双向的lstm,每一个向量2n,是一种特征提取的方法,考虑的上下文的,编码完,就定住了,

elmo:将上下文看成特征,可是无监督的语料和咱们真实的语料仍是有区别的,不必定的符合咱们特定的任务,是一种双向的特征提取。

openai gpt就作了一个改进,也是经过transformer学习出来一个语言模型,不是固定的,经过任务 finetuning,用transfomer代替elmo的lstm。

openai gpt其实就是缺乏了encoder的transformer。固然也没了encoder与decoder之间的attention。

openAI gpt虽然能够进行fine-tuning,可是有些特殊任务与pretraining输入有出入,单个句子与两个句子不一致的状况,很难解决,还有就是decoder只能看到前面的信息。

bert

bert从这几方面作了改进:

  • Masked LM
  • NSP Multi-task Learning
  • Encoder again

bert为何更好呢?

  • 单向信息流的问题 ,只能看前面,不能看后面,其实预料里有后面的信息,只是训练语言模型任务特殊要求只能看后面的信息,这是最大的一个问题。
  • 其次是pretrain 和finetuning 几个句子不匹配。
    在这里插入图片描述
    bert的输入是两个句子,分割符sep,cls表示开始,对输入的两个句子,使用位置编码, segment embeding 根据这个能够知道 该词属于哪一个句子,学习会更加简单。能够很清楚知道第一句子须要编码什么信息,第二个句子能够编码什么信息。
    在这里插入图片描述
    单向信息流的问题,换一个任务来处理这个问题。

单向信息流问题:mask ml 有点相似与完形填空,根据上下文信息猜其中信息,计算出最大几率,随机丢掉15%的词来bert来进行预测,考虑先后双向的信息,怎么搞两个句子?

-50%几率抽连续句子 正样本1

50%几率抽随机句子 负样本 0

这样学习到两个句子的关系,能够预测句子关系,在一些问答场景下很重要。

finetuning:

单个句子的任务,咱们拿第一个cls向量,上面接一些全链接层,作一个分类,标注的数据 fine-tuningbert参数也包括全链接的一个参数,为何选择第一个?
bert任务仍是预测这个词,预测的时候会参考其余的词,如eat自己仍是吃的语义,直接根据eat去分类,显然是不能够的,cls没有太多其余词的语义,因此它的语义彻底来自其余的语义 来自整个句子,编码了整个句子的语义,用它作能够,固然也能够得出全部结果进行拼接后,再来进行预测。

注意:

  • 使用中文模型,不要使用多语言模型
  • max_seq_length 能够小一点,提升效率
  • 内存不够,须要调整 train_batch_size
  • 有足够多的领域数据,能够尝试 Pretraining

bert的实际应用比较简单,不过多赘述内容,推荐简单的demo样例:连接:


AIMI-CN AI学习交流群【1015286623】获取更多AI资料,扫码加群:
在这里插入图片描述
分享技术,乐享生活:欢迎关注咱们的公众号,每周推送AI系列资讯类文章,欢迎您的关注!
在这里插入图片描述