现在谈EMLO,倒是有点食之微味,弃之可惜的意思。2018年,BERT的横空出世撼动了NLP的半壁江山,nlper无不知晓,多项刷榜记录让多数奋战在一线钻研算法的工程师们一刹那觉得自己的努力也仅仅只是感动了自己而已,自然而然,BERT的风光掩盖了ELMO。
但是,我个人觉得,从word2vec,glove到ELMO,BERT,ELMO算是一个比较精彩的转折点吧,有着承前启后的作用,于是,今天就来小谈下ELMO。
为什么出现了ELMO?
在word2vec的时代,词向量是上下文无关的,然而在语言中一词多义的现象是很常见的,比如may,有可能的意思,也有五月的意思;apple,是可以吃的苹果,还是那个apple公司,完全取决于语境。在答案选择领域,那么多复杂的模型,无非不就是为了获得句子的语义信息,句子由词组成,细微处看,就是在摸索词之间的联系与含义,如果一个词没有根据下游任务改变自己的能力,那么往往就需要外界力量去推动她来展示不同层面的意思,而这个外界力量就是那些复杂的模型结构。那么,何不追本溯源,从一开始就让词向量拥有可以根据不同下游任务而变换的能力呢?ELMO因此诞生。
双向语言模型
那么其损失函数语言模型标准的最大化似然函数:
上面的双向语言模型其实就是统计语言模型的一个近似,什么是统计语言模型呢?统计语言模型就是通过统计方法计算一个句子的概率的模型。以前向语言模型为例,我们可以根据这个概率公式来计算下一个词出现的概率。比如“the cat sat on the mat”,我们可以根据“the cat sat on the”来预测下一个词是“mat”的概率,有种完形填空的味道。
ELMO要点
一、模型结构
从图的结构上来看,我们可以很清晰的看到ELMO模型的主要结构就是L层的双向LSTM,对于L层的双向lstm语言模型,一共会有有2L+1个representations。在多层模型中,浅层往往蕴含的是句法,语法信息,而高层蕴含的是语义信息,因此你可以选择ELMO中各层的输出作为最后的输出,也可以将各层的输出进行综合作为最后的输出。
上面2个公式就可以很好的说明了整个流程:ELMO 经过 L 层的双向语言模型, 然后将字符级表示, 每层的隐层输出组合起来, 形成一个2L + 1 个向量。是不同层的参数经过softmax结果(也就是说),值得一提的是, 缩放因子是考虑到双向语言模型中的每一层的输出具有不同的分布,其某种程度上相当于在 Weighting 前对每一层的向量做 Layer Normalization。 论文中有提到,如果将每层向量提前做Normalization, 也能够有所帮助[1]。
论文的作者有预训练好的ELMo模型,同时LSTM的层数L=2,我们以2层的ELMO来具体看ELMO的结构。
二、模型精髓
三、ELMO缺点
四、ELMO词向量使用方式
论文中提到, 使用ELMO 有两种方式:
论文中还提到, 适当的 Dropout 或者在损失中加入L2正则是有帮助的。
五、ELMO实践
搬运一下!
有三种方法可以使用预训练好的elmo模型。
一、elmo官方allenNLP发布的基于pytorch实现的版本[4];
二、elmo官方发布的基于tensorflow实现的版本[5];
三、tensorflow-hub中google基于tensorflow实现的elmo的版本[6]。
本节内容介绍第三个版本,tensorflow-hub
下面看代码的简单上手使用,大家可能需要先安装tensorflow_hub。
import tensorflow_hub as hub
# 加载模型
elmo = hub.Module("https://tfhub.dev/google/elmo/2", trainable=True)
# 输入的数据集
texts = ["the cat is on the mat", "dogs are in the fog"]
embeddings = elmo(
texts,
signature="default",
as_dict=True)["default"]
上述代码中,hub.Module加载模型,第一次会非常慢,因为要下载模型,甚至可能要科学上网。该模型是训练好的模型,也就是lstm中的参数都是固定的。下面的代码是另一种实现,我们可以看到区别在于输入的数据格式不一样!
elmo = hub.Module("https://tfhub.dev/google/elmo/2", trainable=True)
# 另一种方式输入数据
tokens_input = [["the", "cat", "is", "on", "the", "mat"],
["dogs", "are", "in", "the", "fog", ""]]
# 长度,表示tokens_input第一行6一个有效,第二行5个有效
tokens_length = [6, 5]
# 生成elmo embedding
embeddings = elmo(
inputs={
"tokens": tokens_input,
"sequence_len": tokens_length
},
signature="tokens",
as_dict=True)["default"]
EMLO可以以batch的形式训练,但是我在测试上面方法的时候发现有2个问题!
目前还在跑模型,总结用法后会放上来,如果感兴趣,请关注我的 github 以及我的 知乎专栏
Reference:
1.ELMO: Deep contextualized word representations
2.Jozefowicz R, Vinyals O, Schuster M, et al. Exploring the limits of language modeling[J]. arXiv preprint arXiv:1602.02410, 2016.
3.NLP的游戏规则从此改写?从word2vec, ELMo到BERT
4.https://github.com/allenai/allennlp/blob/master/tutorials/how_to/elmo.md
5.https://github.com/allenai/bilm-tf
6.https://tfhub.dev/google/elmo/2