ELMo模型计算详解

ELMo模型计算详解

写在前面

本文记录本人在学习ELMo模型时的记录,具体为解析了在Google的开源实现中给出的源码中,论文中各个模块的输入输出维度变化。希望可以对读者学习ELMo模型时有些帮助。

另外,本章图片内容参考了b站up主自然卷小蛮的视频,在此声明(https://www.bilibili.com/video/BV12L411T7Vh)

ELMo(Embeddings from Language Models)是一个深度学习框架,用于生成上下文感知的词嵌入。这个模型由Allen Institute for Artificial Intelligence的研究人员在2018年开发,并在论文“Deep contextualized word representations”中提出。ELMo的出现标志着自然语言处理(NLP)技术在理解语言上下文和词义的深度方面迈出了重要的一步。

在ELMo之前,词向量技术如Word2Vec和GloVe已经能够捕获一定的语义信息,并在各种NLP任务中取得了显著的成功。然而,这些模型生成的是静态的词嵌入,即每个词在任何上下文中的表示都是固定不变的。这种静态表示无法解决词义消歧问题,也无法充分捕捉语言的复杂性和动态性。ELMo模型的出现旨在解决这一问题。

模型方法

ELMo 模型的网络的整体结构如下图所示。 输入是一个句子,将句子输入到 Character-aware highway encoder 字符编码层,然后经过两层双向 LSTM ,最后通过 softmax 层,然后得到预测的单词结果或者进行损失计算。

ELMo模型整体结构

ELMo模型输入

ELMo模型的输入是一个句子,例如"She opened her book."。由于在Character-aware highway encoder中我们会详细处理单词并提取其特征,所以这里我们将句子作为ELMo模型的输入传入到Character-aware highway encoder层中。

Character-aware highway encoder

character-CNN

我们首先来看 Character-aware highway encoder 层,总体结构如图下所示。

在这里插入图片描述
Character-CNN层的输入是单个单词的字符序列。我们会对每个单词进行处理得到固定维度的向量,然后使用CNN卷积进行特征提取。下面进行依次介绍。char-CNN展开后的模型细节如图所示。

char-CNN 内部更详细的展示

首先,每个字符通过字符嵌入(character embeddings)被转换为固定维度的向量。设字符总数为 n n n,字符嵌入的维度为 d d d,单词最多由 L L L个字符组成,句子最多有 k k k个单词,则输入的每个单词将会转化成矩阵 V c h a r n e w ∈ R L × d V_{char}^{new} \in \mathbb{R}^{L \times d} VcharnewRL×d。具体来说,将每个字符用one-hot的方式进行表示,每个字符就是 n × 1 n \times 1 n×1维的向量,我们通过线性变换,将每个字符的维度从 n n n压缩为 d d d,然后限定单词的最大字符数,即可把每个单词的维度固定为 d × L d \times L d×L,即
V c h a r n e w = V c h a r o n e − h o t W c + b c V_{char}^{new} = V_{char}^{one-hot} W_c + b_c Vcharnew=VcharonehotWc+bc
其中 W c ∈ R n × d W_c \in \mathbb{R}^{n \times d} WcRn×d 是对应的权重矩阵, b c ∈ R d × 1 b_c \in \mathbb{R}^{d \times 1} bcRd×1 为权重矩阵 W c W_c Wc对应的置偏值, V c h a r o n e − h o t ∈ R d × n V_{char}^{one-hot} \in \mathbb{R}^{d \times n} VcharonehotRd×n为字符的one-hot向量, V c h a r n e w V_{char}^{new} Vcharnew V c h a r o n e − h o t V_{char}^{one-hot} Vcharonehot从维度 n × 1 n \times 1 n×1 映射为维度 d × 1 d \times 1 d×1后的字符的向量,通常 n > d n > d n>d

这种字符嵌入的方式与Word2Vec中的两种词嵌入方式不同,Word2Vec中的两种方法都是把 单词 转换为one-hot向量,而在ELMo的输入中,将 字符 转换为one-hot向量,使用矩阵表示单词,这样可以从字符层面挖掘单词的特征。

通过上面的字符嵌入,我们就可以用字符的向量来构建单词的向量。在ELMo中,规定一个单词的最大字符个数不超过 L L L,超过 L L L时会进行截断,不足 L L L时会使用特殊字符的字符编码进行末尾填充。这样我们可以用 V w o r d ∈ R d × L V_{word} \in \mathbb{R}^{d \times L} VwordRd×L表示一个单词,即
V w o r d = V t = [ V c h a r 1 n e w , V c h a r 2 n e w , … , V c h a r L n e w ] = [ V c h a r 1 o n e − h o t , V c h a r 2 o n e − h o t , … , V c h a r L o n e − h o t ] W c + b c V_{word} = V_{t} = [V_{char1}^{new},V_{char2}^{new},\dots, V_{charL}^{new}] = [V_{char1}^{one-hot},V_{char2}^{one-hot}, \dots, V_{charL}^{one-hot}]W_c + b_c Vword=Vt=[Vchar1new,Vchar2new,,VcharLnew]=[Vchar1onehot,Vchar2onehot,,VcharLonehot]Wc+bc
V w o r d = [ v 1 , 1 w o r d v 1 , 2 w o r d … v 1 , L w o r d v 2 , 1 w o r d v 2 , 2 w o r d … v 2 , L w o r d … … … … v d , 1 w o r d v d , 2 w o r d … v d , L w o r d ] V_{word} = \left[\begin{matrix} v_{1,1}^{word} & v_{1,2}^{word} & \dots & v_{1,L}^{word} \\ v_{2,1}^{word} & v_{2,2}^{word} & \dots & v_{2,L}^{word} \\ \dots & \dots & \dots & \dots \\ v_{d,1}^{word} & v_{d,2}^{word} & \dots & v_{d,L}^{word} \\ \end{matrix}\right] Vword= v1,1wordv2,1wordvd,1wordv1,2wordv2,2wordvd,2wordv1,Lwordv2,Lwordvd,Lword
其中, V c h a r i n e w V_{chari}^{new} Vcharinew是单词中第 i i i个字符的嵌入向量。这样我们就完成了character-embedding的过程。 V w o r d = V t V_{word} = V_{t} Vword=Vt 表示当前输入的第 t t t个单词的单词矩阵。

下面介绍AllenNLP中实现的ELMo,character-embedding处理的方式。

在AllenNLP的ELMo的character-embedding中,利用Unicode 字符级对单词的每个字符进行编码。在Unicode 字符集中 0 − 255 0-255 0255共有 256 256 256个字符,加上(单词的开始)、(单词的结束)、 (句子的开始)、(句子的结束)、(单词补齐符)和(句子补齐符)这 6 6 6个特殊字符,一共有 262 262 262个字符,构成了字符集表示中的字符表,即 n = 262 n = 262 n=262。ELMo的思想是给每个字符生成一个固定维度地随机向量,在AllenNLP的ELMo的character-embedding实现中,这 262 262 262 个字符向量会被固定为维度为 16 × 1 16 \times 1 16×1(字符嵌入维度为 16 16 16 d = 16 d = 16 d=16)的向量,采用的方法是将 262 262 262 个字符以one-hot向量的形式进行表示,随后通过线性变换的形式转为换固定维度为 16 × 1 16 \times 1 16×1的向量。

在AllenNLP的ELMo实现中, L = 50 L = 50 L=50 n = 262 n = 262 n=262 d = 16 d = 16 d=16,我们以单词 opened 为例子,首先将其分解成 ‘o’,‘p’,‘e’,‘n’,‘e’,‘d’,共 6 6 6个字符,分别使用相应的字符向量表示,由于单词向量使用 50 50 50个字符向量固定,后面 44 44 44个 字符均使用填充,这样我们就将其固定成字符数量大小为 50 50 50 。于是我们就可以完成 opened 这个单词的编码。此时单词的维度$ 16 \times 50$。这里由于AllenNLP中的嵌入维度较大不方便展示,简单的嵌入例子参考章节ELMo-demo简单的ELMo例子中的字符嵌入过程。

CNN

对于一个句子经过 character-embedding 之后,就会进入 CNN 层,CNN 的核心是使用卷积神经网络。我们考虑一个单词,其字符表示为 v w o r d v_{word} vword v w o r d v_{word} vword是一个 d × L d \times L d×L的矩阵 d d d是每个字符的嵌入维度, L L L是单词的最大长度,则我们可以定义卷积操作:
对于给定卷积核 K K K
K = [ K 1 , K 2 , … , K f ] , K j = [ k 1 , 1 , j k 1 , 2 , j … k 1 , w , j k 2 , 1 , j k 2 , 2 , j … k 2 , w , j … … … … k d , 1 , j k d , 2 , j … k d , w , j ] K = [K_1, K_2, \dots, K_f] , \quad K_j = \left[\begin{matrix} k_{1,1,j} & k_{1,2,j} & \dots & k_{1,w,j} \\ k_{2,1,j} & k_{2,2,j} & \dots & k_{2,w,j} \\ \dots & \dots & \dots & \dots \\ k_{d,1,j} & k_{d,2,j} & \dots & k_{d,w,j} \end{matrix}\right] K=[K1,K2,,Kf],Kj= k1,1,jk2,1,jkd,1,jk1,2,jk2,2,jkd,2,jk1,w,jk2,w,jkd,w,j
其尺寸为 d × w × f d\times w \times f d×w×f,其中:

  • K K K表示卷积核矩阵集合(张量), K j K_j Kj表示卷积核矩阵, k d , w , j k_{d,w,j} kd,w,j表示卷积核矩阵中各个位置的元素值。
  • d d d是卷积核覆盖的字符嵌入维度(与输入维度相匹配),
  • w w w是卷积核的宽度(覆盖的字符数) ,
  • f f f是该卷积核输出的特征数量(或称为过滤器数量)。
  • j = 1 , 2 , … , f j = 1, 2, \dots, f j=1,2,,f

卷积操作的输出 c c c对于每个特征图 j j j的每个位置 i i i在单词长度方向上可以表示为:
c i , j = ∑ m = 1 d ∑ n = 1 w v m , n w o r d k m , n , j + b c n n j c_{i, j} = \sum_{m = 1}^{d} \sum_{n = 1}^{w} v^{word}_{m,n} k_{m,n,j} + b_{cnn}^{j} ci,j=m=1dn=1wvm,nwordkm,n,j+bcnnj
这里, b C N N j ∈ R b_{CNN}^{j} \in \textbf{R} bCNNjR是与过滤器 K j K_j Kj关联的偏置项。输出的维度 c c c
( L − w + 1 ) × f (L - w + 1) \times f (Lw+1)×f,假设没有填充(padding)和步长(stride)为 1 1 1

在卷积后进行最大池化操作,最大池化在每个特征图上独立进行,选取每个特征图中的最大值。对于每个过滤器 K j K_j Kj,池化操作可表示为
c ^ j = max ⁡ ( c 1 , j , c 2 , j , … , c L − w + 1 , j ) , ( j = 1 , 2 , … , f ) \hat{c}_j = \max(c_{1,j}, c_{2,j}, \dots, c_{L- w + 1, j}), \quad (j = 1, 2, \dots, f) c^j=max(c1,j,c2,j,,cLw+1,j),(j=1,2,,f)
最终,池化后的所有特征 c ^ j \hat{c}_j c^j被拼接起来形成一个特征向量 y y y,用作单词的嵌入表示:
y t = ( c ^ 1 , c ^ 2 , … , c ^ F ) y_t = (\hat{c}_1, \hat{c}_2, \dots, \hat{c}_F) yt=(c^1,c^2,,c^F)
其中 F F F是过滤器的总数量(每个卷积核的过滤器相加求和得到总的过滤器数量),则 Y = [ y 1 , y 2 , … , y t , … , y n ] Y = [y_1, y_2, \dots, y_t, \dots, y_n] Y=[y1,y2,,yt,,yn] F × n F \times n F×n维向量。随后,我们将一个个的单词向量 y t y_t yt传入 highway-connection层。

在AllenNLP的ELMo的character-CNN中,包含了 7 种过滤器,分别是 16 × \times × 1 × \times × 32、16 × \times × 2 × \times × 32、16 × \times × 3 × \times × 64、16 × \times × 4 × \times × 128、16 × \times × 5 × \times × 256、16 × \times × 6 × \times × 512、16 × \times × 7 × \times × 1024。过滤器尺寸依次为32、32、64、128、256、512、1024。

通过卷积层后通过池化层,顺着 1 1 1 这一维度进行取最大(MaxPool)也就是将 16 行(在图中就是纵向压缩)通过取最大压缩成 1 1 1 行,也就是将 16 × 50 16 \times 50 16×50 通过池化(取最大)变成 1 × 50 1 \times 50 1×50。我们将得到一个个的 vector 顺着 1 1 1 这一维度进行拼接,可以得到一个 1 × 2048 1 \times 2048 1×2048 的 vector。

highway-connection

接下来是两层的 highway-connection,Highway 网络层的输出是经过门控调节的特征表示,这些表示为后续层(如双向LSTM层)提供了更加精细调整的输入,对于每个时间步的输入是 y t y_t yt。输出的特点包括:

  • 保留与变换:Highway层通过两个主要的门控机制实现信息的保留与变换——一个是变换门(T门),另一个是携带门(C门)。变换门控制有多少当前层的原始信息需要被变换,而携带门控制有多少原始信息需要不加修改地传递到下一层。
  • 门控特征表示:因此,Highway层的输出是原始输入特征的一个门控版本,其中一部分特征被保留并直接传递,而另一部分特征经过变换以提供额外的信息或调整。

变换门
T = σ ( W T y t + b T ) T = \sigma(W_Ty_t + b_T) T=σ(WTyt+bT)

其中 σ \sigma σ 是sigmoid激活函数,确保输出在0和1之间,表示每个特征的转换程度。 y t ∈ R p × 1 y_t \in \mathbb{R}^{p \times 1} ytRp×1 是输入特征, W T ∈ R p × p W_T \in \mathbb{R}^{p \times p} WTRp×p b T ∈ R p × 1 b_T \in \mathbb{R}^{p \times 1} bTRp×1 是变换门的权重和偏置, T ∈ R p × 1 T \in \mathbb{R}^{p \times 1} TRp×1

携带门
C = 1 − T C = 1 - T C=1T
携带门的计算很简单,就是1减去变换门的输出,确保变换和携带的总和为1,这样可以保持信息的完整性, C ∈ R p × 1 C \in \mathbb{R}^{p \times 1} CRp×1

输出
z t = T ⊙ g ( W H y t + b H ) + C ⊙ y t z_t = T \odot g(W_Hy_t + b_H) + C \odot y_t zt=Tg(WHyt+bH)+Cyt

其中, y t ∈ R p × 1 y_t \in \mathbb{R}^{p \times 1} ytRp×1 是输入特征, W H ∈ R p × p W_H \in \mathbb{R}^{p \times p} WHRp×p是变换操作的权重, b H ∈ R p × 1 b_H \in \mathbb{R}^{p \times 1} bHRp×1为对应的置偏值, g ( W H y t + b H ) g(W_Hy_t + b_H) g(WHyt+bH)
是对输入 y t y_t yt 的非线性变换(通常是ReLU激活函数),
T T T是变换门的激活, C C C是携带门的激活,而 z t ∈ R p × 1 z_t \in \mathbb{R}^{p \times 1} ztRp×1 是该 Highway 层的输出, ⊙ \odot 是点乘。

通过这样的设计,Highway 层使得网络能够自适应地调节信息的流动,既能保留对后续处理有用的重要信息,也能对输入特征进行必要的变换,这对于深层次的语义理解尤为重要。

在AllenNLP的ELMo中,进行运算完highway-connection后我们得到结果还是 1 × 2048 1 \times 2048 1×2048 的 vector。最后的 MLP 层就是一层线性映射,将维度为 2048 2048 2048 的 vector 压缩成 512 512 512 维的 vector。

MLP

MLP在此处就是对highway-connection得到的特征进行压缩,然后输入给双向LSTM,具体来说就是一个简单的线性映射,即
u t = W c h a r − c n n − m l p z t + b c h a r − c n n − m l p u_t = W_{char-cnn-mlp}z_t + b_{char-cnn-mlp} ut=Wcharcnnmlpzt+bcharcnnmlp
其中, z t ∈ R p × 1 z_t \in \mathbb{R}^{p \times 1} ztRp×1是输入特征。假设需要映射到的维度大小是 m m m,则 u t ∈ R m × 1 u_t \in \mathbb{R}^{m \times 1} utRm×1 W c h a r − c n n − m l p ∈ R m × p W_{char-cnn-mlp} \in \mathbb{R}^{m \times p} WcharcnnmlpRm×p b c h a r − c n n − m l p ∈ R m × 1 b_{char-cnn-mlp} \in \mathbb{R}^{m \times 1} bcharcnnmlpRm×1是该全连接层的权重矩阵和置偏。

在AllenNLP的ELMo的此处的MLP中,使用 MLP 对 1 × \times × 2048 的 vector 进行处理,得到 1 × \times × 2048 的 vector 作为输入进入双向 LSTM 层。

bidrectional LSTM

接下来就是 ELMo 的核心,两层双向 LSTM。双层双向LSTM得输入是上层输出的单词向量得集合,即
U = ( u 1 , u 2 , … , u n ) U = (u_1, u_2, \dots, u_n) U=(u1,u2,,un)
其中 u t ∈ R m × 1 u_t \in \mathbb{R}^{m \times 1} utRm×1 表示当前单词的向量表示(或者当前时刻单词的向量表示), n n n表示一共有多少个单词(有多少个时刻),且 U ∈ R m × n U \in \mathbb{R}^{m \times n} URm×n

双向LSTM结构包括前向和后向两个LSTM网络,能够捕获上下文信息。我们从LSTM再到双向LSTM对其进行描述,具体如下一小结。

LSTM

我们先简单回忆LSTM的结构与计算方法。LSTM的模型结构如图\ref{ELMo-LSTM}所示。 u t u_t ut 是时间步 t t t 的输入,维度为 m × 1 m \times 1 m×1 h t h_t ht表示当前时刻隐藏层输入, c t c_t ct表示当前时刻当前状态单元 W f W_f Wf b f b_f bf W i W_i Wi b i b_i bi W C W_C WC b C b_C bC W o W_o Wo b o b_o bo分别为LSTM层各个门和模块的权重矩阵和置偏, h 0 h_0 h0 c 0 c_0 c0通常初始化为 0 0 0向量,权重矩阵和置偏通常随机初始化。
LSTM模型结构图

遗忘门(Forget Gate)
遗忘门的计算公式为
f t = σ ( W f ⋅ [ h t − 1 , u t ] + b f ) f_t = \sigma(W_f \cdot [h_{t-1}, u_t] + b_f) ft=σ(Wf[ht1,ut]+bf)
其中, W f W_f Wf 是权重矩阵,维度为 h × ( h + m ) h \times (h + m) h×(h+m) b f b_f bf 是偏置,维度为 h × 1 h \times 1 h×1 h h h是隐藏层维度, σ \sigma σ 是sigmoid函数。

输入门(Input Gate)
输入门的计算公式为
i t = σ ( W i ⋅ [ h t − 1 , u t ] + b i ) i_t = \sigma(W_i \cdot [h_{t-1}, u_t] + b_i) it=σ(Wi[ht1,ut]+bi)
c ~ t = tanh ⁡ ( W C ⋅ [ h t − 1 , u t ] + b C ) \tilde{c}_t = \tanh(W_C \cdot [h_{t-1}, u_t] + b_C) c~t=tanh(WC[ht1,ut]+bC)
W i W_i Wi W C W_C WC 是权重矩阵,维度为 h × ( h + m ) h \times (h + m) h×(h+m) b i b_i bi b C b_C bC 是偏置,维度为 h × 1 h \times 1 h×1

单元状态更新
单元状态更新计算公式为
c t = f t ⊙ c t − 1 + i t ⊙ c ~ t c_t = f_t \odot c_{t-1} + i_t \odot \tilde{c}_t ct=ftct1+itc~t
c t c_t ct c t − 1 c_{t-1} ct1 的维度为 h × 1 h \times 1 h×1

输出门(Output Gate)
输出门的计算公式为
o t = σ ( W o ⋅ [ h t − 1 , u t ] + b o ) o_t = \sigma(W_o \cdot [h_{t-1}, u_t] + b_o) ot=σ(Wo[ht1,ut]+bo)
h t = o t ⊙ tanh ⁡ ( c t ) h_t = o_t \odot \tanh(c_t) ht=ottanh(ct)
W o W_o Wo 是权重矩阵,维度为 h × ( h + m ) h \times (h + m) h×(h+m) b o b_o bo 是偏置,维度为 h × 1 h \times 1 h×1

以上就是LSTM模块的计算,理解了单个LSTM的计算我们就可以进一步计算双向LSTM和双层双向LSTM。为了方便表示,我们将计算过程封装为
h t = LSTM ( u t , h t − 1 ) h_t = \text{LSTM}(u_t, h_{t - 1}) ht=LSTM(ut,ht1)

双向结构

双向LSTM的模型结构如图下所示,在ELMo模型的bidLSTM中的LSTM模块的输入 u t u_t ut 是时间步 t t t 的字符嵌入或词嵌入,维度为 m × 1 m \times 1 m×1 h → t \overrightarrow{h}_t h t表示当前时刻正向LSTM隐藏层输入, h ← t \overleftarrow{h}_t h t 表示当前时刻反向LSTM隐藏层输入,其维度为 m × 1 m \times 1 m×1,通常正向的隐藏层 h → 0 \overrightarrow{h}_0 h 0和反向的隐藏层 h ← t \overleftarrow{h}_t h t均随机初始化或者初始化为值全为 0 0 0的向量或者值全为 1 1 1的向量。 u t u_t ut通过与 h → t − 1 \overrightarrow{h}_{t-1} h t1拼起来构成LSTM的输入,传入正向的LSTM,进行LSTM中的步骤计算,输出 h → t \overrightarrow{h}_{t} h t传入后一个LSTM模块,不断迭代,将每个时间步的隐藏层输出 h → t \overrightarrow{h}_{t} h t序列作为该正向LSTM模块的输出。同理, u t u_t ut通过与 h ← t + 1 \overleftarrow{h}_{t+1} h t+1拼起来构成LSTM的输入,传入正向的LSTM,进行LSTM中的步骤计算,输出 h ← t \overleftarrow{h}_{t} h t传入前一个LSTM模块,不断迭代,将每个时间步的隐藏层输出 h ← t \overleftarrow{h}_{t} h t序列作为该反向LSTM模块的输出。

双向LSTM

对于每一个 u t u_t ut,正向LSTM计算表示为
h → t = LSTM + ( h → t − 1 , u t ) \overrightarrow{h}_{t} = \text{LSTM}_{+}(\overrightarrow{h}_{t-1}, u_t) h t=LSTM+(h t1,ut)
其中 h t → \overrightarrow{h_t} ht h t − 1 → ∈ R m × 1 \overrightarrow{h_{t-1}} \in \mathbb{R}^{m \times 1} ht1 Rm×1 LSTM + \text{LSTM}_{+} LSTM+表示正向的LSTM运算。

对于每一个 u t u_t ut,反向LSTM计算表示为
h ← t = LSTM − ( h ← t + 1 , u t ) \overleftarrow{h}_{t} = \text{LSTM}_{-}(\overleftarrow{h}_{t+1}, u_t) h t=LSTM(h t+1,ut)
其中 h t ← \overleftarrow{h_t} ht h t − 1 ← ∈ R m × 1 \overleftarrow{h_{t-1}} \in \mathbb{R}^{m \times 1} ht1 Rm×1 LSTM − \text{LSTM}_{-} LSTM表示正向的LSTM运算。

于是有

  • 前向LSTM从左到右处理输入序列,生成隐藏状态序列 h → 1 , h → 2 , … , h → n \overrightarrow{h}_1, \overrightarrow{h}_2, \dots, \overrightarrow{h}_n h 1,h 2,,h n.
  • 后向LSTM从右到左处理输入序列,生成隐藏状态序列 h ← 1 , h ← 2 , … , h ← n \overleftarrow{h}_1, \overleftarrow{h}_2, \dots, \overleftarrow{h}_n h 1,h 2,,h n.

我们将结果记为
H → = [ h → 1 , h → 2 , … , h → n ] \overrightarrow{H} = [\overrightarrow{h}_1, \overrightarrow{h}_2, \dots, \overrightarrow{h}_n] H =[h 1,h 2,,h n]
H ← = [ h ← 1 , h ← 2 , … , h ← n ] \overleftarrow{H} = [\overleftarrow{h}_1, \overleftarrow{h}_2, \dots, \overleftarrow{h}_n] H =[h 1,h 2,,h n]
其中 h ← t \overleftarrow{h}_t h t h → t ∈ R m × 1 \overrightarrow{h}_t\in \mathbb{R}^{m \times 1} h tRm×1 H ← \overleftarrow{H} H H → ∈ R m × n \overrightarrow{H} \in \mathbb{R}^{m \times n} H Rm×n

双层双向LSTM

在ELMo中并不是简单地设置一层双向LSTM,而是使用两层。具体计算方式是将第一层双向LSTM中得到的正向LSTM的隐藏层向量传入第二层正向的LSTM,将第一层的双向LSTM中的得到的反向LSTM的隐藏层向量传入第二层反向的LSTM。ELMo中的双层双向LSTM如图\ref{ELMo-double-ward-Bid-LSTM}所示。
双层双向LSTM

与上面计算第一层的双向LSTM类似,我们用公式进行描述对于每一个 h → t \overrightarrow{h}_{t} h t,正向LSTM计算表示为
h → t n e w = LSTM + ( h → t − 1 n e w , h → t ) \overrightarrow{h}_{t}^{new} = \text{LSTM}_{+}(\overrightarrow{h}_{t-1}^{new},\overrightarrow{h}_{t}) h tnew=LSTM+(h t1new,h t)
其中 h t → n e w \overrightarrow{h_t}^{new} ht new h t − 1 n e w → ∈ R m × 1 \overrightarrow{h_{t-1}^{new}} \in \mathbb{R}^{m \times 1} ht1new Rm×1 LSTM + \text{LSTM}_{+} LSTM+表示正向的LSTM运算。

对于每一个 h ← t \overleftarrow{h}_{t} h t,反向LSTM计算表示为
h ← t n e w = LSTM − ( h ← t + 1 n e w , h ← t ) \overleftarrow{h}_{t}^{new} = \text{LSTM}_{-}(\overleftarrow{h}_{t+1}^{new}, \overleftarrow{h}_{t}) h tnew=LSTM(h t+1new,h t)
其中 h t ← n e w \overleftarrow{h_t}^{new} ht new h t ← n e w ∈ R m × 1 \overleftarrow{h_t}^{new} \in \mathbb{R}^{m \times 1} ht newRm×1 LSTM − \text{LSTM}_{-} LSTM表示正向的LSTM运算。

于是有

  • 前向LSTM从左到右处理输入序列将上面生成的第一层隐藏状态传递给下一层,生成隐藏状态序列 h → 1 n e w , h → 2 n e w , … , h → n n e w \overrightarrow{h}_1^{new}, \overrightarrow{h}_2^{new}, \dots, \overrightarrow{h}_n^{new} h 1new,h 2new,,h nnew.
  • 后向LSTM从右到左处理输入序列将上面生成的第一层隐藏状态传递给下一层,生成隐藏状态序列 h ← 1 n e w , h ← 2 n e w , … , h ← n n e w \overleftarrow{h}_1^{new}, \overleftarrow{h}_2^{new}, \dots, \overleftarrow{h}_n^{new} h 1new,h 2new,,h nnew.

我们将结果记为
H → n e w = [ h → 1 n e w , h → 2 n e w , … , h → n n e w ] \overrightarrow{H}^{new} = [\overrightarrow{h}_{1}^{new}, \overrightarrow{h}_{2}^{new}, \dots, \overrightarrow{h}_{n}^{new}] H new=[h 1new,h 2new,,h nnew]
H ← n e w = [ h ← 1 n e w , h ← 2 n e w , … , h ← n n e w ] \overleftarrow{H}^{new} = [\overleftarrow{h}_{1}^{new}, \overleftarrow{h}_{2}^{new}, \dots, \overleftarrow{h}_{n}^{new}] H new=[h 1new,h 2new,,h nnew]
其中 h ← t n e w \overleftarrow{h}_{t}^{new} h tnew h → t n e w ∈ R m × 1 \overrightarrow{h}_{t}^{new}\in \mathbb{R}^{m \times 1} h tnewRm×1 H ← n e w \overleftarrow{H}^{new} H new H → n e w ∈ R m × n \overrightarrow{H}^{new} \in \mathbb{R}^{m \times n} H newRm×n

bid-LSTM输出

在通常情况下,最终输出 S = [ s 1 ⃗ , s 2 ⃗ , … , s 2 m ⃗ ] S = [\vec{s_1}, \vec{s_2}, \dots, \vec{s_{2m}}] S=[s1 ,s2 ,,s2m ] 是对前面的双层双向LSTM进行了如下操作:
对于每个时间步,将两层得到的正向LSTM的隐藏层输出与反向LSTM的隐藏层输出相加,即
h → t + h → t n e w , h ← t + h ← t n e w \overrightarrow{h}_t + \overrightarrow{h}_t^{new}, \quad \overleftarrow{h}_t + \overleftarrow{h}_t^{new} h t+h tnew,h t+h tnew
然后再将得到的结果拼成一个更长的向量得到结果,即
s t ⃗ = [ h → t + h → t n e w ; h ← t + h ← t n e w ] \vec{s_t} = [\overrightarrow{h}_t + \overrightarrow{h}_t^{new}; \overleftarrow{h}_t + \overleftarrow{h}_t^{new}] st =[h t+h tnew;h t+h tnew]
如果每个方向的隐藏状态维度为 m m m,则 s t ⃗ \vec{s_t} st 的维度为 2 m × 1 2m \times 1 2m×1

于是我们得到
S = [ s 1 ⃗ , s 2 ⃗ , … , s 2 m ⃗ ] S = [\vec{s_1}, \vec{s_2}, \dots, \vec{s_{2m}}] S=[s1 ,s2 ,,s2m ]
其中 s t ⃗ ∈ R 2 m × 1 \vec{s_t} \in \mathbb{R}^{2m \times 1} st R2m×1 S ∈ R 2 m × n S \in \mathbb{R}^{2m \times n} SR2m×n

MLP and Softmax

为了得到对应的单词,我们通过一层线性映射,将单词向量表示转换为高维的表示,然后通过Softmax得到每个时刻 t t t单词的概率分布,从而得到要预测的单词。即对于每一个时间步
q t ⃗ = W s s t ⃗ + b s \vec{q_t} = W_s \vec{s_t} + b_s qt =Wsst +bs
其中, q t ⃗ ∈ R V × 1 \vec{q_t} \in \mathbb{R}^{V \times 1} qt RV×1为映射后的向量、 W s ∈ R V × 2 h W_s \in \mathbb{R}^{V \times 2h} WsRV×2h为映射的权重矩阵、 b s ∈ R V × 1 b_s \in \mathbb{R}^{V \times 1} bsRV×1为对应的置偏, V V V为单词表的维度。

写成矩阵的形式为
Q = W s S + b s Q = W_s S + b_s Q=WsS+bs
其中, Q = [ q 1 ⃗ , q 2 ⃗ , … , q n ⃗ ] ∈ R V × n Q = [\vec{q_1}, \vec{q_2}, \dots, \vec{q_n}] \in \mathbb{R}^{V \times n} Q=[q1 ,q2 ,,qn ]RV×n q t ⃗ ∈ R V × 1 \vec{q_t} \in \mathbb{R}^{V \times 1} qt RV×1 S ∈ R 2 m × n S \in \mathbb{R}^{2m \times n} SR2m×n s t ⃗ ∈ R 2 m × 1 \vec{s_t} \in \mathbb{R}^{2m \times 1} st R2m×1

随后我们使用Softmax将向量 q t ⃗ = [ q 1 , q 2 , … , q V ] T \vec{q_t} = [q_1, q_2, \dots, q_V]^T qt =[q1,q2,,qV]T转换为概率分布向量 p i ⃗ \vec{p_i} pi ,即
p i ⃗ = Softmax ( q i ⃗ ) = exp ⁡ ( q i ) ∑ k = 1 V exp ⁡ ( q k ) \vec{p_i} = \text{Softmax}(\vec{q_i}) = \frac{\exp(q_i)}{ \sum\limits_{k=1}^{V} \exp(q_k)} pi =Softmax(qi )=k=1Vexp(qk)exp(qi)
其中, q t ⃗ ∈ R V × 1 \vec{q_t} \in \mathbb{R}^{V \times 1} qt RV×1为映射后的向量、 p t ⃗ ∈ R V × 1 \vec{p_t} \in \mathbb{R}^{V \times 1} pt RV×1为转换为概率分布后的向量。

写成矩阵的形式为
P = ( p 1 ⃗ , p 2 ⃗ , … , p n ⃗ ) P = (\vec{p_1},\vec{p_2}, \dots, \vec{p_n}) P=(p1 ,p2 ,,pn )
其中 p t ⃗ ∈ R V × 1 \vec{p_t} \in \mathbb{R}^{V \times 1} pt RV×1 为每个单词对应位置的词向量表示的概率分布, P ∈ R V × n P \in \mathbb{R}^{V \times n} PRV×n为整个句子的矩阵向量。

ELMo模型输出

实际上MLP and Softmax层输出的概率分布矩阵实际上就是ELMo模型的输出,即上下文感知的表示。通过这个概率分布,我们可以从词汇表中查出需要预测的单词。

损失函数

在计算得到bid-LSTM的结果之后,我们将得到的词向量表示映射到整个单词集合,然后使用Softmax计算概率分布,然后使用交叉熵来计算ELMo模型的损失。

在此处的Softmax运算之前,由于我们的在双向LSTM中的输出维度是 2 h 2h 2h,我们要将其映射为词汇表的维度 V V V,随后我们使用softmax将向量q转换为概率分布,最后使用交叉熵损失来计算ELMo模型的损失,即正确的标签为one-hot向量,然后与预测的向量一起进行交叉熵损失计算,得到每一时刻的损失,即
Loss t = − ∑ i = 1 V t a g i log ⁡ ( p i ) \text{Loss}_t= - \sum_{i = 1}^{V} tag_i\log(p_i) Losst=i=1Vtagilog(pi)
其中, p ∈ R V × 1 p \in \mathbb{R}^{V \times 1} pRV×1 为预测概率分布向量, t a g ∈ R V × 1 tag \in \mathbb{R}^{V \times 1} tagRV×1为正确的标签, Loss t \text{Loss}_t Losst表示在 t t t时刻时得到的损失。

最后再将所有的损失进行求均值得到总的损失,即
Loss = 1 T ∑ i = 1 T Loss i \text{Loss} = \frac{1}{T} \sum_{i = 1}^{T} \text{Loss}_i Loss=T1i=1TLossi
其中, T T T为总的时刻数, Loss i \text{Loss}_i Lossi t t t时刻的损失。