1. 概述
Bidirectional Encoder Representation from Transformers(BERT)[1],即双向Transformer的Encoder表明,是2018年提出的一种根据上下文的预练习模型,经过很多语料学习到每个词的一般性embedding形式,学习到与上下文无关的语义向量表明,以此完成对多义词的建模。与预练习言语模型ELMo[2]以及GPT[3]的关系如下图所示:
Embeddings from Language Models(ELMo)[2],Generative Pre-Training(GPT)[3]以及Bidirectional Encoder Representation from Transformers(BERT)[1]三者都是根据上下文的预练习模型,也都是选用两阶段的进程,榜首阶段是运用无监督的方法对言语模型进行预练习,第二阶段经过监督的方法在具体言语使命上进行Fine-tuning。不同的是在ELMo中选用的双向的LSTM算法;在GPT中选用的特征提取算法是Transformer[4],且是单向的Transformer言语模型,相比较于ELMo中的LSTM模型,根据Transformer的模型具有更好的特征提取才能;在BERT中同样选用了根据Transformer的特征提取算法,与GPT中不同的是:
- 榜首,在BERT中的Transformer是一个双向的Transformer模型,更进一步提高了特征的提取才能
- 第二,GPT中选用的是Transformer中的Decoder模型,BERT中选用的是Transformer中的Encoder模型。
2. 算法原理
2.1. Transformer结构
Transformer的网络结构如下图所示:
在Transformer中,包含了Encoder和Decoder两个部分,在对言语模型的练习中,摒弃了根据RNN和CNN的传统做法,选用了根据Attention的模型,可以提高特征的抽取才能,一起更利于并行的学习。BERT选用了Transformer的Encoder部分,如上图中的红色框内的部分。
2.2. BERT的基本原理
BERT是根据上下文的预练习模型,BERT模型的练习分为两步:榜首,pre-training;第二,fine-tuning。
在pre-training阶段,首要会经过很多的文本对BERT模型进行预练习,可是,标示样本是十分珍贵的,在BERT中则是选用很多的未标示样本来预练习BERT模型。在fine-tuning阶段,会针对不同的下游使命恰当改造模型结构,一起,经过具体使命的样本,重新调整模型中的参数。
为了使得BERT可以适配更多的应用,模型在pre-training阶段,运用了Masked Language Model(MLM)和Next Sentence Prediction(NSP)两种使命作为模型预练习的使命,其间MLM可以学习到词的Embedding,NSP可以学习到语句的Embedding。在Transformer中,输入中会将词向量与方位向量相加,而在BERT中,为了能适配上述的两个使命,即MLM和NSP,这儿的Embedding包含了三种Embedding的和,如下图所示:
其间,Token Embeddings是词向量,榜首个单词是CLS标志,可以用于之后的分类任,Segment Embeddings用来区别两种语句,这是在预练习阶段,针对NSP使命的输入,Position Embeddings是方位向量,可是和Transformer中不一样,与词向量一样,是经过学习出来的。此处包含了两种符号,一个是[CLS]
,可以理解为整个输入特征的向量表明;另一个是[SEP]
,用于区分不同的语句。
2.2.1. 预练习之MLM
Masked Language Model的原理是随机将一些词替换成[MASK]
,在练习的进程中,经过上下文信息来猜测被mask的词。文献[1]中给出了如下的比如:“my dog is hairy”,此时被随机选中的词是“hairy”,则样本被替换成“my dog is [MASK]”,练习的意图是要使得BERT模型可以猜测出此处的“[MASK]”即为“hairy”。一起,随机替换的概率为15%15\%。一起,关于这15%15\%的随机挑选,分为以下的三种情况:
- 选中词的80%80\%替换成[MASK],如:“my dog is [MASK]”
- 选中词的10%10\%随机替换,如替换成apple,即:“my dog is apple”
- 选中词的10%10\%保持不变,即:“my dog is hairy”
这样做的意图是让模型知道该方位对应的token可以是任何的词,这样就强迫模型去学习更多的上下文信息,不会过多的关注于当前的token。
2.2.2. 预练习之NSP
Next Sentence Prediction的意图是让模型理解两个橘子之间的关系,练习的输入是两个语句,BERT模型需求判别后一个语句是不是前一个语句的下一句。在Input中,有Segment Embeddings,便是符号的不同的语句。在挑选练习数据时,输入语句A和B,B有50%的概率是A的下一句,具体的比如如:
2.3. BERT的网络结构
根据Transformer的Encoder结构,关于单个的Attention进程,有如下的BERT结构:
具体的Attention的核算逻辑可以参见参考文献[5],文献[5]关于Transformer的基本原理有详细的介绍。参考文献[6]给出了BERT的代码完成,其间transformer部分的代码如下所示:
def transformer_model(input_tensor,
attention_mask=None,
hidden_size=768,
num_hidden_layers=12,
num_attention_heads=12,
intermediate_size=3072,
intermediate_act_fn=gelu,
hidden_dropout_prob=0.1,
attention_probs_dropout_prob=0.1,
initializer_range=0.02,
do_return_all_layers=False):
"""Multi-headed, multi-layer Transformer from "Attention is All You Need".
This is almost an exact implementation of the original Transformer encoder.
See the original paper:
https://arxiv.org/abs/1706.03762
Also see:
https://github.com/tensorflow/tensor2tensor/blob/master/tensor2tensor/models/transformer.py
Args:
input_tensor: float Tensor of shape [batch_size, seq_length, hidden_size].
attention_mask: (optional) int32 Tensor of shape [batch_size, seq_length,
seq_length], with 1 for positions that can be attended to and 0 in
positions that should not be.
hidden_size: int. Hidden size of the Transformer.
num_hidden_layers: int. Number of layers (blocks) in the Transformer.
num_attention_heads: int. Number of attention heads in the Transformer.
intermediate_size: int. The size of the "intermediate" (a.k.a., feed
forward) layer.
intermediate_act_fn: function. The non-linear activation function to apply
to the output of the intermediate/feed-forward layer.
hidden_dropout_prob: float. Dropout probability for the hidden layers.
attention_probs_dropout_prob: float. Dropout probability of the attention
probabilities.
initializer_range: float. Range of the initializer (stddev of truncated
normal).
do_return_all_layers: Whether to also return all layers or just the final
layer.
Returns:
float Tensor of shape [batch_size, seq_length, hidden_size], the final
hidden layer of the Transformer.
Raises:
ValueError: A Tensor shape or parameter is invalid.
"""
if hidden_size % num_attention_heads != 0:
raise ValueError(
"The hidden size (%d) is not a multiple of the number of attention "
"heads (%d)" % (hidden_size, num_attention_heads))
attention_head_size = int(hidden_size / num_attention_heads) # self-attention的头
input_shape = get_shape_list(input_tensor, expected_rank=3)
batch_size = input_shape[0] # batch的大小
seq_length = input_shape[1] # 语句长度
input_width = input_shape[2]
# The Transformer performs sum residuals on all layers so the input needs
# to be the same as the hidden size.
if input_width != hidden_size:
raise ValueError("The width of the input tensor (%d) != hidden size (%d)" %
(input_width, hidden_size))
# We keep the representation as a 2D tensor to avoid re-shaping it back and
# forth from a 3D tensor to a 2D tensor. Re-shapes are normally free on
# the GPU/CPU but may not be free on the TPU, so we want to minimize them to
# help the optimizer.
prev_output = reshape_to_matrix(input_tensor)
all_layer_outputs = []
for layer_idx in range(num_hidden_layers):
with tf.variable_scope("layer_%d" % layer_idx):
layer_input = prev_output
with tf.variable_scope("attention"): # attention的核算
attention_heads = []
with tf.variable_scope("self"):
attention_head = attention_layer(
from_tensor=layer_input,
to_tensor=layer_input,
attention_mask=attention_mask,
num_attention_heads=num_attention_heads,
size_per_head=attention_head_size,
attention_probs_dropout_prob=attention_probs_dropout_prob,
initializer_range=initializer_range,
do_return_2d_tensor=True,
batch_size=batch_size,
from_seq_length=seq_length,
to_seq_length=seq_length)
attention_heads.append(attention_head) # 多头注意力
attention_output = None
if len(attention_heads) == 1:
attention_output = attention_heads[0]
else:
# In the case where we have other sequences, we just concatenate
# them to the self-attention head before the projection.
attention_output = tf.concat(attention_heads, axis=-1) # concat多头的输出
# Run a linear projection of `hidden_size` then add a residual
# with `layer_input`.
with tf.variable_scope("output"):
attention_output = tf.layers.dense(
attention_output,
hidden_size,
kernel_initializer=create_initializer(initializer_range))
attention_output = dropout(attention_output, hidden_dropout_prob) # dropout
attention_output = layer_norm(attention_output + layer_input) # layer norm
# The activation is only applied to the "intermediate" hidden layer.
with tf.variable_scope("intermediate"):
intermediate_output = tf.layers.dense(
attention_output,
intermediate_size,
activation=intermediate_act_fn,
kernel_initializer=create_initializer(initializer_range))
# Down-project back to `hidden_size` then add the residual.
with tf.variable_scope("output"):
layer_output = tf.layers.dense(
intermediate_output,
hidden_size,
kernel_initializer=create_initializer(initializer_range))
layer_output = dropout(layer_output, hidden_dropout_prob)
layer_output = layer_norm(layer_output + attention_output)
prev_output = layer_output
all_layer_outputs.append(layer_output)
if do_return_all_layers:
final_outputs = []
for layer_output in all_layer_outputs:
final_output = reshape_from_matrix(layer_output, input_shape)
final_outputs.append(final_output)
return final_outputs
else:
final_output = reshape_from_matrix(prev_output, input_shape)
return final_output
2.3.1. BERT是双向Transformer
GPT模型中运用的是Transformer的Decoder部分(对原始的Decoder部分做了少许改动),而BERT则是选用了Transformer的Encoder部分,下图给出了两者在一个Transformer模块上的比照:
从上图中可以看出,仅有的不同是在Multi-Head Attention部分,如图中的红色框,在BERT中运用的是Multi-Head Attention,而GPT中运用的是Masked Multi-Head Attention。在Masked Multi-Head Attention是应用在Decoder阶段的生成模型,即在tt时间,根据t−1t-1时间及之前的词猜测tt时间的词,关于tt时间以及tt时间之后的词是不行见的,因而Masked Multi-Head Attention是一个单向的模型,一起不便于并行。
关于Multi-Head Attention,其核算方法如下图所示:
在核算Attention的进程中,会一起运用上文和下文的信息,仅仅关于上图中的“it_”会以一定的概率被[MASK]
符号替换。因而,BERT模型是一个双向的言语模型,一起,BERT中的Attention核算利于并行核算。
2.3.2. Fine Tune
关于NLP的使命,首要分为四大类:
- 序列标示,如中文分词,词性标示,命名实体辨认(特色:语句中每个单词要求模型根据上下文都要给出一个分类类别)
- 分类使命,如文本分类,情感核算(特色:总体给出一个分类类别)
- 语句关系判别,如QA,语意改写(特色:给定两个语句,模型判别出两个语句是否具备某种语义关系)
- 生成式使命,如机器翻译,文本摘要,写诗造句,看图说话(特色:输入文本内容后,需求自主生成别的一段文字)
而生成式使命在Transformer中有了详细的介绍。关于其他的三类使命,典型的场景如下图所示:
榜首,语句对的分类使命,即输入是两个语句,输入如下图所示:
输出是BERT的榜首个[CLS]
的隐含层向量C∈RHC\in \mathbb{R}^H,在Fine-Tune阶段,加上一个权重矩阵W∈RKHW\in \mathbb{R}^{K\times H},其间,KK为分类的类别数。终究经过Softmax函数得到终究的输出概率。
第二,单个语句的分类。相关于语句对的分类使命来说要简单,其输入是单个语句,如下图所示:
其输出同语句对分类的输出。
第三,问答使命,其输入如语句对的输入,不同的是榜首个语句是问题,第二个语句是段落。
第四,针对每个词的tagging,其输入如单个语句的输入,输出是针对每个token的隐含层输出进行tagging。
3. 总结
BERT模型的提出关于NLP预练习的作用有了较大提高,在ELMo模型的基础上运用了Self-Attention作为文本特征的挖掘,一起避免了GPT模型中的单向言语模型,充分运用文本中的上下文特征。
参考文献
[1] Devlin J , Chang M W , Lee K , et al. BERT: Pre-training of Deep Bidirectional Transformers for Language Understanding[J]. 2018.
[2] Peters M , Neumann M , Iyyer M , et al. Deep Contextualized Word Representations[J]. 2018.
[3] Radford A, Narasimhan K, Salimans T, et al. Improving language understanding by generative pre-training[J]. 2018.
[4] Vaswani A, Shazeer N, Parmar N, et al. Attention is all you need[J]. Advances in neural information processing systems, 2017, 30.
[5] Transformer的基本原理
[6] github.com/google-rese…