文章目录
之前介绍的Word Vector方法如Word2Vec, GloVe, fastText等存在两个大问题
- 对于一个 word type 总是是用相同的表示,不考虑这个 word token 出现的上下文,比如 star 这个单词,有天文学上的含义以及娱乐圈中的含义不同,我们可以进行非常细粒度的词义消歧
- 我们对一个词只有一种表示,但是单词有不同的方面,包括语义,句法行为,以及表达 / 含义
一、ELMO
1.TagLM – “Pre-ELMo”
TagLM的思想是想要获得单词在上下文的意思,但标准的 RNN 学习任务只在 task-labeled 的小数据上(如 NER ),可以通过半监督学习的方式在大型无标签数据集上训练 NLM,而不只是词向量。TagLM使用与上文无关的单词嵌入 + RNN model 得到的 hidden states 作为特征输入,如下图所示,

左侧Char CNN / RNN + Token Embedding 作为第一层 bi-LSTM 的输入得到的 hidden states 与右侧 预训练的 bi-LM(冻结的) 的 hidden states 连接起来输入到第二层的 bi-LSTM 中

2.ELMo: Embeddings from Language Models
ELMO的基本思想是使用长上下文而不是上下文窗口学习 word token 向量

ELMO利用双向的LSTM结构,对于某个语言模型的目标,在大量文本上进行预训练,从LSTM layer中得到contextual embedding,其中较低层的LSTM代表了比较简单的语法信息,而上层的LSTM捕捉的是依赖于上下文的语义信息。对于下游的任务,再将这些不同层的向量线性组合,再做监督学习。
ELMo目标是 performant 但语言模型不要太大
- 使用2个biLSTM层
- (仅)使用字符CNN构建初始单词表示
- 2048 个 char n-gram filters 和 2 个 highway layers,512 维的 projection
- 4096 dim hidden/cell LSTM状态,使用 512 dim的对下一个输入的投影
- 使用残差连接
- 绑定 token 的输入和输出的参数(softmax),并将这些参数绑定到正向和反向LMs之间
- TagLM 中仅仅使用堆叠LSTM的顶层,ELMo 认为BiLSTM所有层都是有用的
对于k位置的标记,ELMO模型用2L+1个向量 R 来表示,其中1个是不依赖于上下文的表示,通常是用之前提及的word embedding或者是基于字符的CNN来得到 x 。L层前向 LSTM和 反向 LSTM每层会分别产生一个依赖于上文/下文的表示 h ,我们可以将他们一起简计。
得到每层的embedding后,对于每个下游的任务,我们可以计算其加权的表示即下图中的 ELMo

- γ衡量ELMo对任务的总体有用性,是为特定任务学习的全局比例因子
- s是 softmax 归一化的混合模型权重,是 BiLSTM 的加权平均值的权重,对不同的任务是不同的
采用了ELMO预训练产生的contextual embedding之后,在各项下游的NLP任务中,准确率都有显著提高。
二、ULMfit
ULMfit的基本思想:
- 在大型通用领域的无监督语料库上使用 biLM 训练
- 在目标任务数据上调整 LM
- 对特定任务将分类器进行微调

使用大型的预训练语言模型是一种提高性能的非常有效的方法。随着计算的扩大,得到了诸如GPT、BERT等Transformer模型

三、Transformer
Google所提基于transformer的seq2seq整体结构如下所示:

其包括6个结构完全相同的编码器,和6个结构完全相同的解码器,其中每个编码器和解码器设计思想完全相同,只不过由于任务不同而有些许区别,整体详细结构如下所示:

由于基于transformer的翻译任务已经转化为分类任务(目标翻译句子有多长,那么就有多少个分类样本),故在解码器最后会引入fc+softmax层进行概率输出,训练也比较简单,直接采用ce loss即可,对于采用大量数据训练好的预训练模型,下游任务仅仅需要训练fc层即可。下面结合代码和原理进行深入分析。
1.编码器
(1)词向量+位置编码
首先将单词使用词嵌入例如word2vec方法转化成n维向量,之后进行位置编码。
位置编码的意义在于因为transformer内部没有类似RNN的循环结构,没有捕捉顺序序列的能力。为了解决这个问题,在编码词向量时会额外引入了位置编码position encoding向量表示两个单词i和j之间的距离,简单来说就是在词向量中加入了单词的位置信息。
在论文中采用的是sin-cos规则来进行位置编码,具体做法是:

将向量的维度切分为奇数行和偶数行,偶数行采用sin函数编码,奇数行采用cos函数编码,然后按照原始行号拼接
def get_position_angle_vec(position):
# hid_j是0-511,d_hid是512,position表示单词位置0~N-1
return [position / np.power(10000, 2 * (hid_j // 2) / d_hid) for hid_j in range(d_hid)]
# 每个单词位置0~N-1都可以编码得到512长度的向量
sinusoid_table = np.array([get_position_angle_vec(pos_i) for pos_i in range(n_position)])
# 偶数列进行sin
sinusoid_table[:, 0::2] = np.sin(sinusoid_table[:, 0::2]) # dim 2i
# 奇数列进行cos
sinusoid_table[:, 1::2] = np.cos(sinusoid_table[:, 1::2]) # dim 2i+1
在最后将词向量编码和位置编码向量相加,得到多头注意力层输入
(2)多头注意力层
在介绍多头注意力之前首先介绍一下自注意力。首先定义三个可学习矩阵 W (相当于线性层,维度一般为 词向量维度 * 词向量维度),将 X 和三个矩阵相乘得到 Q、K、V三个输出。然后将Q和K进行点乘计算向量相似性并进行归一化;采用softmax转换为概率分布;将概率分布和V进行加权求和即可。可由下图表示:

多头注意力相当于多个自注意力的集成,并在两方面提高了注意力层的性能:
- 它扩展了模型专注于不同位置的能力
- 它给出了注意力层的多个表示子空间
简单来说多头注意力就是类似于分组操作,将输入X分别输入到8个self-attention层中,得到8个Z矩阵输出,之后对结果按列拼成一个大的特征矩阵,特征矩阵经过一层全连接后得到输出。另外,多头注意力加入了残差设计和层归一化操作,目的是为了防止梯度消失,加快收敛。

单头注意力代码:
class ScaledDotProductAttention(nn.Module):
''' Scaled Dot-Product Attention '''
def __init__(self, temperature, attn_dropout=0.1):
super().__init__()
self.temperature = temperature
self.dropout = nn.Dropout(attn_dropout)
def forward(self, q, k, v, mask=None)

本文介绍了从ELMo到BERT的发展历程,涵盖了TagLM、ULMfit、Transformer等关键技术。ELMo通过双向LSTM改进了词向量,而Transformer则革新了序列到序列的学习方式。BERT进一步实现了深度双向表示预训练,通过Masked LM和Next Sentence Prediction任务,大幅提升了NLP任务的表现。
最低0.47元/天 解锁文章
3855

被折叠的 条评论
为什么被折叠?



