ELMo(Embeddings from Language Models)详解

ELMo词嵌入模型:解决一词多义问题

一、为什么要提出ELMo 

        ELMo(Embeddings from Language Models)是由华盛顿大学于2018年3月提出的一种词嵌入模型。ELMo源于论文《Deep contextualized word representations》(Matthew E. Peters等),主要是为了解决“一词多义”的问题。传统的词向量模型,如Word2Vec和GloVe,虽然在许多任务中表现良好,但存在明显的不足。这些模型生成的词向量是静态的,即同一个词在不同的上下文中总是具有相同的向量表示,无法适应不同的语境。例如,“apple”这个词既可以指水果,又可以指苹果公司,二者具有完全不同的含义,但传统模型无法体现这种差异。而且传统模型没有捕捉到词性等语法信息,也没有解决一词多义问题。而ELMo通过引入上下文信息,为每个词语生成动态的词向量,能更准确地捕捉词语的语义信息。

二、ELMo模型结构详解

       ELMo模型由三部分组成:字符集嵌入模块、双层双向LSTM模块和动态词向量表征模块。网络结构如上图所示。

  • 字符级嵌入模块:该模块输入为字符级别的,而非单词级别。(1)先将输入词拆分为字符,如"apple"被拆分为"a"、"p"、"p"、"l"、"e",每个字符采用one-hot编码表示。(2)通过嵌入层将one-hot向量变为低维的稠密向量。(3)将每个字符的稠密向量组成单词的稠密矩阵(4)采用CNN卷积对单词的稠密矩阵进行局部采样,捕捉字符间的形态学特征(如词根、前后缀等)。(5)对卷积后的特征图进行最大池化操作,提取每个通道的最显著特征。(6)池化后的向量输入Highway层中,通过门控机制控制信息流动,增强非线性表达能力。
  • 双层双向LSTM模块:(1)将Highway层输出作为输入,输入第一层双向LSTM中,正向和反向LSTM的输入均为Highway层输出。正向和反向LSTM的输出进行拼接(维度拼接,维度变为2倍)后,输入至第二层双向LSTM中。(2)将第二层中的正向和反向LSTM的输出进行拼接后进行输出。
  • 动态词向量表征模块:每个词的表征由三部分加权求得:(1)字符集嵌入模块的输出(底层特征,捕获词形信息);(2)第一层LSTM的输出(中层特征,侧重句法);(3)第二层LSTM的输出(高层特征,侧重语义)。

下面对每个模块进行详细讲解。

2.1 字符级嵌入模块

2.1.1 输入层与嵌入层 

      首先,每个字符通过字符嵌入(character embeddings)被转换为固定维度的向量。假设字符总数为,字符嵌入的维度为,先将每个字符用one-hot的方式进行表示,每个字符就是的向量。通过线性变换,将每个字符的维度从压缩为

       其中,为对应的权重矩阵,维度为为对应的偏置项,维度为为字符的one-hot向量,从维度映射为维度后的字符的向量,通常

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

        通过上面的字符嵌入,我们就可以用字符的向量来构建单词的向量。在ELMo中,规定一个单词的最大字符个数不超过,超过时会进行截断,不足时会使用特殊字符的字符编码进行填充。这样,我们可以用表示一个单词,即:

V_{word}=\begin{bmatrix} v_{1,1}^{word} &v_{1,2}^{word} & ... &v_{1,L}^{word} \\ v_{2,1}^{word} & v_{2,2}^{word} &... &v_{2,L}^{word} \\ ... &... & ... &... \\ v_{d,1}^{word} & v_{d,2}^{word} & ... &v_{d,L}^{word} \end{bmatrix}

       其中,是单词中第i个字符的嵌入向量。这样,我们就完成了character-embedding的过程。

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

        在AllenNLP的ELMo的character-embedding中,利用Unicode 字符级对单词的每个字符进行编码,其中n=262(n=262也是一个经验值,它可以覆盖大部分情况)。在AllenNLP的ELMo的character-embedding实现中,这 262 个字符向量会被固定为维度为(字符嵌入维度为16,即d=16)的向量,采用的方法是将262个字符以one-hot向量的形式进行表示,随后通过线性变换的形式转为固定维度为的向量。

       在AllenNLP的 EMLo实现中,,我们以单词opened为例子,首先将其分解成‘o’,‘p’,‘e’,‘n’,‘e’,‘d’,共计6个字符,分别使用相应的字符向量表示。由于单词向量使用50个字符向量福鼎,后面44个字符均使用填充,这样我们就将其固定成字符数量大小为50.于是我们就可以完成opened这个单词的编码。此时单词的维度。这里由于AllenNLP中嵌入维度较大不方便展示。

2.1.2 卷积层与池化层

       对于一个单词经过character-embedding之后,就会进行卷积层。卷积层的核心是使用卷积神经网络CNN。我们考虑一个单词,其字符表示为是一个的矩阵,d是每个字符的嵌入维度,L是单词的最大长度,则我们可以进行卷积操作:

      对于给定卷积核K:

,

      卷积核尺寸为,其中:

  • 表示卷积核矩阵集合(张量),表示卷积核矩阵,表示卷积核中各个位置的元素值
  • 是卷积核覆盖的字符嵌入维度(AllenNLP中,卷积核覆盖的字符维度与字符嵌入维度相同)
  • 是卷积核的宽度(覆盖的字符数)
  • 是该卷积核输出的特征数量(或称为过滤器数量)

卷积操作的输出对于每个特征图的每个位置在单词长度方向上可以表示为:

输出的维度,假设没有填充,并且步长为1。

在卷积后进行最大池化操作,最大池化在每个特征图上独立进行,选取每个特征图中的最大值。对于每个过滤器,池化操作可表示为:

最终,池化后的所有特征被拼接起来形成一个特征向量,用作单词的嵌入表示:

以上得到了一个单词的向量。由于后续会输入至LSTM中,所以会对每个单词进行上述操作,形成向量。随后,我们将单词向量传入highway层中。

在AllenNLP的ELMo的character-CNN中,包含了7种过滤器,分别为。过滤器尺寸依次为32、32、64、128、256、512和1024。

通过卷积层,得到的输出维度为,然后顺着第一个维度取最大值(最大池化),得到的向量分别为:,然后进行拼接,得到维的向量。

2.1.3 highway层

在ELMo中使用highway层还是借鉴LSTM的做法,引入门控机制,从而解决深层神经网络中的梯度消失问题,并提升模型对长距离依赖关系的建模能力

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

变换门

        其中,是sigmoid激活函数,确保输出在0和1之间,表示每个特征的转换程度。是输入特征,是变换门的权重和偏置。

携带门

携带门的计算很简单,就是1减去变换门的输出,确保变换和携带的总和为1,这样可以保持信息的完整性,

输出

其中,是输入特征,是变换操作的权重,为对应的偏置值,

是对输入的非线性变换(通常是ReLU激活函数),是变换门的激活,是携带门的激活,而是该highway层的输入,是点乘。

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

       在MLP层,就是对highway得到的特征进行压缩,然后输入给双向LSTM,具体来说就是一个简单的线性映射,即:

2.2 双层双向LSTM

为了更具一般性,我们先将双层双向LSTM推广至多层双向LSTM,结构如下图所示:

2.2.1 符号定义

  • 第一层LSTM的输入序列:X=(x_{1},x_{2},...,x_{n}),其中x_{t}\in R^{k}x_{t}为经过MLP层后的输出
  • 层数:共计L层,第l层的参数用上标(l)标记
  • 隐藏层状态维度:每层前向/后向LSTM的隐藏状态维度为h_{size}
  • 合并操作:双向LSTM的输出通常将前向和后向隐藏状态拼接(记作\oplus),维度为2h_{size}

2.2.2 计算过程

 单层单向LSTM的计算过程本文不再赘述,详细可参考 我之前的文章《LSTM思想解析—论文精读(Long Short-Term Memery)》《LSTM思想解析—论文精读(Learning to Forget: Continual Prediction with LSTM)》 

       为了更具一般性,我们讲解多层双向LSTM:

      对于第l-1层的第t个时刻,前向传播输出的隐藏状态为h_{f->t}^{(l-1)},反向传播输出的隐藏状态为h_{b->t}^{(l-1)},两个隐藏状态进行拼接,得到h^{l}_{t}=h_{f->t}^{(l-1)}\oplus h_{b->t}^{(l-1)}

     h^{l}_{t}作为第l层的第t时刻的数据输入(相当于第1层的数据输入X=(x_{1},x_{2},...,x_{n})),分别输入到第l层的第t时刻的前向传播和反向传播LSTM中。第l层的第t时刻的前向传播除了接收h^{l}_{t}作为数据输入外,还接收第l层的第t-1时刻输出的隐藏状态h^{l}_{f->t-1},最终计算出h_{f->t}^{(l)};同理,第l层的第t时刻的反向传播除了接收h^{l}_{t}作为数据输入外,还接收第l层的第t+1时刻输出的隐藏状态h_{b->t+1}^{(l)},最终计算出h_{b->t}^{(l)}。然后再进行拼接操作,形成h^{l+1}_{t}=h_{f->t}^{(l)}\oplus h_{b->t}^{(l)},如此反复。

2.3 动态词向量表征模块

       在这一层,需要将字符级嵌入模块的输出、第一层双向LSTM的输出、第二层双向LSTM的输出进行加权,得到最终的词向量表示。动态加权公式为:ELMo_{k}=\gamma \sum_{j=0}^{L} s_{j}h_{k,j},其中:

  • L:表示总层数(字符级嵌入层+2层LSTM,共计3层)
  • h_{k,j}:第k个词在第j层的输出向量
  • s_{j}:可训练的层权重(会用softmax进行归一化)
  • \gamma:可训练的缩放因子(标量)

三层获取的词向量特征对比

特征维度字符级层LSTM1层LSTM2层
抽象级别词素级语法级语义级
上下文范围单词内部局部(3-5词)全局(整句)
主要功能形态分析语法结构语义理解
敏感度拼写变化词序变化语境变化
典型任务OOV处理词性标注情感分析

三、ELMo模型前向传播与反向传播过程

3.1 前向传播过程

前向传播的整体流程如下:

以句子“I like apples”为例,详细讲解前向传播过程。

3.1.1 字符级嵌入层

(1)将输入单词“apples”进行字符分解:['a','p','p','l','e','s'],然后填充至50字符。

(2)字符嵌入:50x16矩阵

(3)多尺度卷积:

                宽度为3的卷积—>得到128维的特征图

                宽度为4的卷积—>得到128维的特征图

                宽度为5的卷积—>得到128维的特征图

(4)进行最大池化:得到384维的向量

(5)Highway网络:门控特征融合

(6)全链接层:变为512维的向量输出—>h_char

3.1.2 第一层双向LSTM

# 输入序列: [h_I, h_like, h_apples]   h_I, h_like, h_apples为字符级嵌入层输出的向量
# 前向LSTM (→)
→h1_I = LSTM(h_I, →h0)     # 初始状态h0为0向量
→h1_like = LSTM(h_like, →h1_I)
→h1_apples = LSTM(h_apples, →h1_like)

# 后向LSTM (←)
←h1_apples = LSTM(h_apples, ←h0)  # 从右向左
←h1_like = LSTM(h_like, ←h1_apples)
←h1_I = LSTM(h_I, ←h1_like)

# 拼接输出
h1_I = [→h1_I; ←h1_I]      # 2048维  t1时刻输出
h1_like = [→h1_like; ←h1_like]      #t2时刻输出
h1_apples = [→h1_apples; ←h1_apples]   #t3时刻输出

3.1.3 第二层双向LSTM

# 输入序列: [h1_I, h1_like, h1_apples]
# 前向LSTM (→)
→h2_I = LSTM(h1_I, →h0)    #初始状态h0为0向量
→h2_like = LSTM(h1_like, →h2_I)
→h2_apples = LSTM(h1_apples, →h2_like)

# 后向LSTM (←)
←h2_apples = LSTM(h1_apples, ←h0)  # 从右向左
←h2_like = LSTM(h1_like, ←h2_apples)
←h2_I = LSTM(h1_I, ←h2_like)

# 拼接输出
h2_I = [→h2_I; ←h2_I]      # 2048维   t1时刻输出
h2_like = [→h2_like; ←h2_like]        #t2时刻输出
h2_apples = [→h2_apples; ←h2_apples]   #t3时刻输出

3.1.4 语言模型预测

# 前向语言模型 (预测下一个词)
P(like|I) = softmax(W_fw * →h2_I)
P(apples|like) = softmax(W_fw * →h2_like)
P(<EOS>|apples) = softmax(W_fw * →h2_apples)

# 后向语言模型 (预测前一个词)
P(<BOS>|I) = softmax(W_bw * ←h2_I)      # 无前词
P(I|like) = softmax(W_bw * ←h2_like)
P(like|apples) = softmax(W_bw * ←h2_apples)

3.1.5 前向传播示例

假设单词"like"的处理:

字符级输出: [0.21, -0.15, 0.32, ...] (512维)

第一层LSTM:
  前向: [0.82, 0.05, -0.15, ...] (1024维)
  后向: [0.78, -0.12, 0.21, ...] (1024维)
  拼接: [0.82, 0.05, -0.15, ..., 0.78, -0.12, 0.21] (2048维)

第二层LSTM:
  前向: [0.92, -0.15, 0.87, ...] (1024维)
  后向: [0.88, 0.12, 0.91, ...] (1024维)
  拼接: [0.92, -0.15, 0.87, ..., 0.88, 0.12, 0.91] (2048维)

前向预测:
  输入: →h2_like = [0.92, -0.15, 0.87, ...]
  输出: logits = [1.2, 3.5, -0.8, ...] (vocab_size维)
  softmax: P("apples") = 0.85

3.2 反向传播过程

3.2.1 损失函数计算

# 前向损失  连乘通过log函数变为了连加
L_fw = -[log P(like|I) + log P(apples|like) + log P(<EOS>|apples)]

# 后向损失   连乘通过log函数变为了连加
L_bw = -[log P(<BOS>|I) + log P(I|like) + log P(like|apples)]

# 总损失
L_total = L_fw + L_bw

3.2.2 反向传播路径

3.2.3 关键梯度计算(以位置t="like"为例)

(1) 输出层梯度

# 前向输出层
δ_fw_out = (y_pred - y_true)  # y_true = "apples"的one-hot

# 后向输出层
δ_bw_out = (y_pred - y_true)  # y_true = "I"的one-hot

(2) 第二层LSTM梯度

# 前向LSTM梯度
δ_fw_lstm2 = W_fw.T @ δ_fw_out + δ_next_fw  # 来自时间流

# 后向LSTM梯度
δ_bw_lstm2 = W_bw.T @ δ_bw_out + δ_next_bw

(3) LSTM单元内部梯度

# 以第二层前向LSTM为例
# 输入: [h1_like; h1_like] (2048维)
# 遗忘门梯度
df = δ_fw_lstm2 * ot * (1 - tanh(ct)^2 * c_prev * f*(1-f)

# 输入门梯度
di = δ_fw_lstm2 * ot * (1 - tanh(ct)^2 * gt * i*(1-i)

# 输出门梯度
do = δ_fw_lstm2 * tanh(ct) * o*(1-o)

# 候选状态梯度
dg = δ_fw_lstm2 * ot * (1 - tanh(ct)^2 * it * (1 - gt^2)

(4) 字符级嵌入层梯度

# 反向传播至字符嵌入层
δ_char_emb = W_lstm1.T @ δ_lstm1

# 继续反向至Highway网络
δ_highway = (g * δ_char_emb) + ((1-g) * δ_char_emb)  # 简化表示

# 卷积层梯度
δ_conv = unpool(δ_highway)  # 最大池化位置梯度

3.2.4 参数更新

# 通用更新规则
for param in [char_embed, conv_weights, lstm_params, output_weights]:
    param -= learning_rate * ∇L/∇param

3.3 前向传播与反向传播示例

前向传播片段(位置t="like")

输入: h_char = [0.21, -0.15] (简化2维)

LSTM1前向计算:
  →h1 = [0.82, 0.05] (隐藏状态)
LSTM1后向计算:
  ←h1 = [0.78, -0.12]
拼接: h1 = [0.82, 0.05, 0.78, -0.12]

LSTM2前向计算:
  →h2 = [0.92, -0.15]
前向预测:
  logits = W_fw @ →h2 = [0.5*0.92 + (-0.2)*(-0.15), ...] = [0.49, ...]
  softmax = [0.3, 0.6, 0.1]  # 假设词汇表3词
  真实标签: "apples" = [0,1,0]
  损失: -log(0.6) = 0.51

反向传播片段

# 输出层梯度
δ_fw_out = [0.3-0, 0.6-1, 0.1-0] = [0.3, -0.4, 0.1]

# LSTM2梯度 (假设W_fw=[[0.5, -0.2],[0.3,0.1],[ -0.4,0.6]])
δ_fw_lstm2 = W_fw.T @ δ_fw_out = [0.5*0.3 + 0.3*(-0.4) + (-0.4)*0.1, 
                                 -0.2*0.3 + 0.1*(-0.4) + 0.6*0.1] 
                             = [0.15-0.12-0.04, -0.06-0.04+0.06] = [-0.01, -0.04]

# LSTM门梯度计算 (简化)
假设当前LSTM状态:
  f=0.6, i=0.7, o=0.65, c_prev=0.4, c_t=0.5, g=0.3
df = -0.04 * 0.65 * (1-tanh(0.5)^2 * 0.4 * 0.6*(1-0.6) ≈ -0.0002
di = -0.04 * 0.65 * (1-tanh(0.5)^2 * 0.3 * 0.7*(1-0.7) ≈ -0.0001

# 参数更新示例
W_fw += 0.001 * (-δ_fw_out @ →h2.T) = 0.001 * -([0.3,-0.4,0.1] @ [0.92,-0.15])
                    = 0.001 * -[0.3*0.92, -0.4*0.92, 0.1*0.92;
                                 0.3*(-0.15), -0.4*(-0.15), 0.1*(-0.15)]
                    ≈ 0.001 * -[[0.276, -0.368, 0.092], 
                                 [-0.045, 0.06, -0.015]]

参考文章:ELMo模型计算详解-优快云博客

                 【AI大模型】ELMo模型介绍:深度理解语言模型的嵌入艺术

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值