想象你是一位影视导演,手下的演员个个都是“本色演员”——他在《赌神》里演赌神,在《乡村爱情》里还是那副赌神腔调。你换了无数剧本,演员永远是同一张脸、同一套做派。词向量界也曾面临同样的尴尬:传统词向量(Word2Vec、GloVe)给每个词只准备了一张“证件照”,无论“bank“出现在”我去银行存钱“还是”我在河岸钓鱼”,向量都一模一样。可语言中一词多义无处不在,一个固定向量怎么可能装得下所有含义? ELMo 的出现改变了这一切。它像一位“方法派演员”:拿到剧本(句子)后先通读上下文,再调整声线、姿态和眼神(向量),让同一个词在不同语境里呈现出截然不同的气质。ELMo 通过在大规模语料上预训练双向语言模型,让每个词向量“随上下文而流动”。这就是上下文词嵌入的由来。理解 ELMo,你就拿到了理解后来 GPT、BERT 等一切预训练模型的钥匙。

岗位关联

对 NLP 工程师而言,ELMo 是“预训练 + 迁移”范式的启蒙者。掌握它,你就理解了为什么如今“一个任务一个模型”的做法会被彻底淘汰,也为学习 GPT、BERT 等现代预训练模型打下坚实的直觉基础。

目录
  1. 可视化演示
  2. 静态词向量困局
  3. 语言模型基础
  4. ELMo架构原理
  5. 层级权重机制
  6. 训练使用流程
  7. BERT对比分析
  8. 迁移应用实践
  9. 历史意义价值
  10. AI 应用场景
  11. Python 演示
  12. 常见误区
  13. 面试题

可视化演示

本节配有交互动效(进入视口后自动加载,约 3KB)。

双向语言模型(biLM) 前向:左→右预测 后向:右→左预测 ELMo = Σλ_j·h_j 双向隐状态加权融合

静态词向量困局

假设你是一位导演,手下的演员全是“本色演员”——他在《赌神》里演赌神,在《乡村爱情》里还是那副赌神腔调。同一个词(bank)无论走进哪句台词,Word2Vec 都塞给它同一个数字排列。问题是,语言中的“剧本”千变万化:“我去银行存钱”里的 bank 是金融机构,“我在河岸钓鱼”里的 bank 是河堤。一个固定向量,怎么可能同时演好两个角色?

传统词向量经历了两个阶段。第一步是 one-hot 表示,相当于给每个词发一个唯一的“编号牌”:词表有多大,编号牌就有多长,大部分位置全是 0,维度动辄几万。第二步是 Word2Vec / GloVe,用神经网络把编号牌压缩成几百维的稠密向量,让意思相近的词靠得更近。但无论压缩得多漂亮,每个词都只有一张固定“证件照”,不携带任何上下文。一词多义和上下文缺失这两个先天缺陷,始终无法解决。

以 one-hot 为例,它是词向量家族的“原始人”:

wt=[0,0,…,1,…,0]∈R∣V∣\displaystyle \mathbf{w}_t = [0, 0, \ldots, 1, \ldots, 0] \in \mathbb{R}^{|V|}

1. 词表大小 |V|:∣V∣\displaystyle |V|

这是词汇表的规模,比如 5 万个词,one-hot 向量就有 5 万维。维度随词表膨胀,计算和存储都吃不消。

2. 唯一为 1 的位置:wt[i]=1, 当 i=t\displaystyle \mathbf{w}_t[i] = 1, \text{ 当 } i = t

第 t 个词只把自己的位置点亮,其余位置全部熄灭,所以向量之间没有任何“语义距离”可言。

3. 向量所在空间:R∣V∣\displaystyle \mathbb{R}^{|V|}

one-hot 落在 |V| 维的实数空间里。两个不同的词向量夹角为 90 度、内积为 0,计算机完全不知道“猫”和“狗”其实是近亲。

Word2Vec 解决了“把演员塞进化妆间”的问题,但这位演员依然只有一套造型。要让他像方法派演员那样“演谁像谁”,我们必须让向量先看懂剧本——也就是先建模上下文。这正是下一节要登场的语言模型。

语言模型基础

方法派演员拿到剧本后的第一件事是什么?通读全文,搞清每一句台词的来龙去脉。语言模型就是“剧本通读器”:它读一个句子时,逐个词地计算“在已经看到前面这些词的情况下,下一个词最可能是谁”。

ELMo 的前身是经典语言模型。前向语言模型从左到右读句子:给定前 k-1 个词,预测第 k 个词的概率。后向语言模型从右到左读:给定后面所有词,预测当前词。两者合起来,每个词的“视野”就能覆盖整句话(除了自己)。这种“前后夹击”的信息结构,正是 ELMo 让词向量活起来的燃料。

给定长度为 N 的句子 t_1, t_2, ……, t_N,前向语言模型把整句概率拆成“链式”连乘:

p(t1,t2,…,tN)=∏k=1Np(tk∣t1,t2,…,tk−1)\displaystyle p(t_1, t_2, \ldots, t_N) = \prod_{k=1}^{N} p(t_k \mid t_1, t_2, \ldots, t_{k-1})

1. 整句概率:p(t1,t2,…,tN)\displaystyle p(t_1, t_2, \ldots, t_N)

模型要为整个句子打分,判断这句话在人类语言中“像不像话”。

2. 连乘符号:∏k=1N\displaystyle \prod_{k=1}^{N}

把每个词的条件概率逐个相乘,这就是概率论中的链式法则,是语言模型的数学根基。

3. 条件概率项:p(tk∣t1,t2,…,tk−1)\displaystyle p(t_k \mid t_1, t_2, \ldots, t_{k-1})

第 k 个词在“已知前 k-1 个词”前提下的出现概率。预测时用到的“前文”,正是上下文信息的入口。

ELMo 的聪明之处,是把“剧本通读”和“上下文”嫁接在了一起:既然语言模型必须看前文才能预测后文,那它的中间隐状态就天然携带了上下文信息——演员通读剧本时心里的笔记,正好成了塑造角色(词向量)的依据。

ELMo架构原理

方法派演员怎样塑造角色?先看外表(这个词长什么样),再对台词(它和谁搭配),最后体会内心(它在整体语境中的深层含义)。ELMo 的架构也分三步,每一层对应演员揣摩角色的一层深度。

ELMo(Embeddings from Language Models,语言模型词嵌入)用字符级 CNN 把词转成初始嵌入,这样可以优雅处理生僻词和拼写变体;然后把初始嵌入送进两层双向 LSTM。每个位置的每层隐状态,都是“前向+后向”两个方向的拼接,最终形成一个多层上下文表示集合。对句子中第 k 个词,ELMo 会留下三层“工作笔记”:

Rk={xkLM,hk,1LM,hk,2LM}\displaystyle R_k = \{ \mathbf{x}_k^{LM}, \mathbf{h}_{k,1}^{LM}, \mathbf{h}_{k,2}^{LM} \}

其中每一层的双向拼接形式为:

hk,jLM=[h→k,jLM;h←k,jLM]\displaystyle \mathbf{h}_{k,j}^{LM} = [\overrightarrow{\mathbf{h}}_{k,j}^{LM}; \overleftarrow{\mathbf{h}}_{k,j}^{LM}]

1. 初始嵌入:xkLM\displaystyle \mathbf{x}_k^{LM}

字符 CNN 输出的词嵌入,尚未接触上下文,相当于演员的素颜照。

2. 第 j 层双向隐状态:hk,jLM\displaystyle \mathbf{h}_{k,j}^{LM}

第 k 个词经过第 j 层 LSTM 后得到的隐藏向量。

3. 前向分量:h→k,jLM\displaystyle \overrightarrow{\mathbf{h}}_{k,j}^{LM}

前向 LSTM 从句子开头一路读到 k 时刻的隐状态,携带“左边”的信息。

4. 后向分量:h←k,jLM\displaystyle \overleftarrow{\mathbf{h}}_{k,j}^{LM}

后向 LSTM 从句子末尾反读到 k 时刻的隐状态,携带“右边”的信息。

5. 拼接集合:Rk={⋅}\displaystyle R_k = \{ \cdot \}

把三层笔记收进同一个集合,供下游任务按需取用,这正是“深度上下文表示”的由来。

当“bank“出现在”去银行存钱“里,第 1 层可能记下”它后面跟着 save、money 这类金融词“;第 2 层则捕捉”这是关于储户的金融事件“。当它出现在”河岸钓鱼“里,笔记完全不同。同一个演员,在两部戏里的”人物小传”自然分道扬镳。

层级权重机制

导演手上拿着演员的三层表演报告:外形、台词、内心。拍谍战剧时,导演更看重内心戏;拍喜剧时,夸张的外形更重要。导演可以给三层报告分配不同权重,再合成最终表演指导——这就是层级权重机制。

ELMo 每层输出信息类型不同:底层偏词法与拼写、中层偏句法(词性、短语结构)、高层偏语义(词义消歧)。不同下游任务对这些信息的偏好不一样,因此原论文让任务自己学习一组 softmax 权重,把三层加权合成一个 ELMo 向量:

ELMoktask=γtask∑j=02sjtask⋅hk,jLM\displaystyle \text{ELMo}_k^{\text{task}} = \gamma^{\text{task}} \sum_{j=0}^{2} s_j^{\text{task}} \cdot \mathbf{h}_{k,j}^{LM}

1. softmax 层级权重:sjtask=exp⁡(wjtask)∑j′=02exp⁡(wj′task)\displaystyle s_j^{\text{task}} = \frac{\exp(w_j^{\text{task}})}{\sum_{j'=0}^{2} \exp(w_{j'}^{\text{task}})}

把三个可学习的标量转成和为 1 的权重,保证合成的方向性稳定。

2. 加权求和:∑j=02sjtask⋅hk,jLM\displaystyle \sum_{j=0}^{2} s_j^{\text{task}} \cdot \mathbf{h}_{k,j}^{LM}

三项按权重合并成一个向量,相当于导演对三层表演报告做综合决策。

3. 缩放因子:γtask\displaystyle \gamma^{\text{task}}

一个可学习的标量,控制 ELMo 向量整体大小,避免压过下游模型原有的特征。

4. 任务差异:task\displaystyle \text{task}

上标"task"强调权重不是全局唯一的,每个下游任务学到自己的组合方式,这正是 ELMo 能灵活适配多任务的关键。

在 SQuAD 问答任务上,模型学到的权重偏向高层语义层;在 NER 命名实体识别任务上,又偏向中层句法层。导演在不同片场做出不同取舍,ELMo 因此能“见人下菜碟”。

训练使用流程

方法派演员先花数月接受系统训练(预训练),然后空降到各个剧组。到了新剧组,他不需要重上三年学,只需要把已经练就的表演能力“嵌”进角色设定里。

ELMo 的使用分两阶段。第一阶段在大规模通用语料(如维基百科)上训练双层双向语言模型;第二阶段把训练好的 ELMo 冻结,作为特征注入下游任务——典型做法是在下游模型的输入词向量处和输出隐向量处两处拼接 ELMo 向量,下游任务自己的参数照常训练:

L=∑k=1N(log⁡p(tk∣t1,…,tk−1;Θx,Θ→LSTM,Θs)+log⁡p(tk∣tk+1,…,tN;Θx,Θ←LSTM,Θs))\displaystyle \mathcal{L} = \sum_{k=1}^{N} \Big( \log p(t_k \mid t_1, \ldots, t_{k-1}; \Theta_x, \overrightarrow{\Theta}_{\text{LSTM}}, \Theta_s) + \log p(t_k \mid t_{k+1}, \ldots, t_N; \Theta_x, \overleftarrow{\Theta}_{\text{LSTM}}, \Theta_s) \Big)

1. 前向损失项:log⁡p(tk∣t1,…,tk−1;Θx,Θ→LSTM,Θs)\displaystyle \log p(t_k \mid t_1, \ldots, t_{k-1}; \Theta_x, \overrightarrow{\Theta}_{\text{LSTM}}, \Theta_s)

给定词 t_k 前面的词,前向 LSTM 预测 t_k 的对数概率。参数包括共享词嵌入 Θx、前向 LSTM 权重和输出 softmax 层 Θs。

2. 后向损失项:log⁡p(tk∣tk+1,…,tN;Θx,Θ←LSTM,Θs)\displaystyle \log p(t_k \mid t_{k+1}, \ldots, t_N; \Theta_x, \overleftarrow{\Theta}_{\text{LSTM}}, \Theta_s)

给定 t_k 后面的词,后向 LSTM 预测 t_k 的对数概率。后向 LSTM 单独一套参数。

3. 全句求和:∑k=1N\displaystyle \sum_{k=1}^{N}

把每个词在两个方向上的贡献加起来,构成整句的训练信号。

4. 共享参数:Θx,Θs\displaystyle \Theta_x, \Theta_s

两个方向共享字符 CNN 词嵌入和输出 softmax 层,只有 LSTM 参数分前向后向各一套。

预训练是“戏剧学院的通识课”,下游拼接是“剧组里的化妆定妆”——剧组绝不重写演员的功底,只需在服装、台词上做局部调整。这一“冻结 + 拼接”模式,正是预训练词向量走进工程的核心姿势。

BERT对比分析

ELMo 这位方法派演员总是一个方向通读剧本——从左往右读一遍,再从右往左读一遍,最后把两遍笔记合起来。而 BERT 是“全员沉浸式排练”:所有演员同时在场、互相观察,任何一个词的定位都同时参考全场所有人的反应。

ELMo 的“双向”是前向/后向两个 LSTM 独立工作、输出拼接;BERT 的“双向”是 Transformer 的 self-attention 在全句范围内同时建模左右两侧。两者在架构、训练目标、使用方式上存在明显差异:

| 对比维度 | ELMo | BERT |

|---|---|---|

| 骨干网络 | 2 层双向 LSTM | 12/24 层 Transformer |

| 双向方式 | 前向后向拼接 | Self-Attention 并行交互 |

| 训练目标 | 前向+后向语言模型 | Masked LM + 下一句预测 |

| 下游适配 | 特征冻结拼接 | 全参数微调 |

BERT 的掩码训练目标可写成:

∑m∈Mlog⁡p(tm∣t\M;Θ)\displaystyle \sum_{m \in \mathcal{M}} \log p(t_m \mid t_{\backslash \mathcal{M}}; \Theta)

1. 掩码位置集合:M\displaystyle \mathcal{M}

被随机遮挡的词的位置集合,例如句子“我去 [MASK] 存钱”中的 MASK。

2. 条件(剩余词):t\M\displaystyle t_{\backslash \mathcal{M}}

句子中没被遮挡的所有词,作为预测依据。相比 ELMo 只关注单侧,这里左右两侧都能看到。

3. 目标求和:∑m∈Mlog⁡p(tm∣⋅)\displaystyle \sum_{m \in \mathcal{M}} \log p(t_m \mid \cdot)

对每个被遮挡的词计算预测正确度,全部求和后作为训练目标。

ELMo 更像一个刻苦的独白演员,分两次记住台词正、反两面的逻辑;BERT 则像一场即兴群戏,每个词都在全剧组的目光中寻找自己的位置。正因如此,BERT 往往比 ELMo 更强,但也更“吃”算力。

迁移应用实践

方法派演员成名后,各种剧组争相邀约:谍战剧请他演特工,都市剧请他演程序员,法律剧请他演律师。剧组不需要重新培训他——只要把“方法派表演”嵌入角色设定,效果立刻拔群。

ELMo 的价值体现在迁移:用通用语料预训练,再向具体 NLP 任务注入。原论文在问答(SQuAD)、文本分类(SST-5)、命名实体识别(CoNLL 2003)等任务上做了系统实验,ELMo 都是“即插即用”的强特征。在 SQuAD 问答任务上,ELMo 将 F1 提升约 4.7 个百分点;在 SST-5 细粒度情感分类上,准确率提升约 2 个百分点;在 CoNLL 2003 命名实体识别上,F1 提升约 1.2 个百分点。注入方式有两种常见做法:

输入拼接: [xk;ELMok],输出拼接: [hk;ELMok]\displaystyle \text{输入拼接: } [\mathbf{x}_k; \text{ELMo}_k] \quad,\quad \text{输出拼接: } [\mathbf{h}_k; \text{ELMo}_k]

1. 输入拼接:[xk;ELMok]\displaystyle [\mathbf{x}_k; \text{ELMo}_k]

把原始词嵌入和 ELMo 向量沿维度方向连接,作为下游网络第一层的输入。

2. 输出拼接:[hk;ELMok]\displaystyle [\mathbf{h}_k; \text{ELMo}_k]

把下游网络(如 BiLSTM)的隐状态再与 ELMo 向量拼接,送到输出层(如 CRF)。

3. 双处注入:输入与输出同时注入\displaystyle \text{输入与输出同时注入}

一些任务只靠其中一处就有效,两处都加往往效果更好。

问答系统像谍战剧,需要“内心戏”(高层语义)重一点;命名实体识别像法律剧,需要“专业台词”(中层句法)更多。ELMo 提供的多层级特征,正好支持不同剧组“各取所需”。

历史意义价值

方法派演技的出现,改变了整条演艺工业链——从此演员不再只靠本色,而是靠“方法论”走天下。ELMo 之于 NLP,就是那场表演界的革命。

2018 年,ELMo 获得 NAACL 最佳论文,第一次系统地证明:“在超大规模语料上预训练语言模型,再把模型的知识迁移到下游任务”这个范式可以普遍提升多项 NLP 任务的效果。它之前,Word2Vec 只是给词一张静态证件照;它之后,预训练语言模型成为标配。随后 GPT 借用 Transformer 解码器做单向 LM 预训练,BERT 借用 Transformer 编码器做双向掩码预训练——它们都继承了 ELMo 建立的“先在通用语料上学表示、再适配下游任务”的基本套路:

Word2Vec (2013)⟶ELMo (2018)⟶GPT / BERT (2018)\displaystyle \text{Word2Vec (2013)} \quad \longrightarrow \quad \text{ELMo (2018)} \quad \longrightarrow \quad \text{GPT / BERT (2018)}

1. 起点 Word2Vec:2013\displaystyle \text{2013}

静态词向量,每个词一个固定向量,无法感知上下文。

2. 转折点 ELMo:2018年2月\displaystyle \text{2018年2月}

首个将上下文感知引入预训练词向量的系统,证实动态表示可行。

3. 后续模型:GPT / BERT\displaystyle \text{GPT / BERT}

ELMo 之后的半年,GPT 和 BERT 相继出现,预训练范式全面开花。

4. 演进本质:从静态到动态、从任务定制到通用预训练\displaystyle \text{从静态到动态、从任务定制到通用预训练}

这是本节要记住的最重要线索。

ELMo 的局限也很明显:LSTM 串联读句,长距离依赖吃力;“双向拼接”没有真正交叉。但正如方法派演技推动了整个表演理论,ELMo 虽然很快被 BERT 等后来者超越,它的思想遗产——“让词向量随语境流动”——已经深深嵌入了今天所有主流 NLP 模型。

AI 应用场景

保险智能客服意图识别

阶段:特征工程 / 文本表示注入

解决的问题:传统关键词匹配无法理解“我今天被车撞了,理赔款什么时候到账”这种包含因果的复合意图。词袋和 Word2Vec 固定向量把“车撞”和“理赔”当成零散碎片,模型分不清用户到底想理赔还是想投诉。

具体案例:某保险科技公司搭建意图识别系统,先用百万级客服问答语料预训练 ELMo,再冻结 ELMo 特征,在其上训练一个线性分类器。上线后 20 类意图识别的准确率从 82% 提升至 91%,其中“车险理赔进度咨询”和“车险投诉”两类易混淆意图的 F1 分别提升 8 个百分点。

法律文书命名实体识别

阶段:预训练 + 特征注入(下游序列标注)

解决的问题:法律判决书中“当事人姓名、机构名称、案号、金额、日期”边界复杂,Word2Vec 固定向量对“XX银行”这类嵌套名词无能为力。ELMo 的上下文表示可结合相邻词信息,准确切出实体边界。

具体案例:某法律科技公司对 10 万份民事判决书做 NER,用 ELMo 特征 + BiLSTM-CRF,人名、机构、金额三类实体 F1 达 92.5%,比仅用 Word2Vec 提升 3.8 个百分点,案号识别准确率也显著提升。

电商评论情感分类

阶段:迁移学习 / 分类任务特征集成

解决的问题:用户评论常出现转折:“手机颜值高,但电池太拉了”。词袋模型会因同时出现“高”和“拉”而摇摆。ELMo 结合上下文的动态向量能捕捉转折结构,判断整体情感偏负面。

具体案例:某电商平台对商品评论做四分类情感分析(好评、中评、差评、含剧透),使用 ELMo 拼接 LSTM 分类器,Macro-F1 较 Word2Vec 提升 2.4 个百分点,对含转折词评论的识别准确率提升 6 个百分点。

Python 演示

python53 行
import torchimport torch.nn as nn  class SimpleELMo(nn.Module):    """Minimal ELMo: two-layer BiLSTM + layer weights"""     def __init__(self, vocab_size, emb_dim=16, hidden_dim=32):        super().__init__()        self.emb = nn.Embedding(vocab_size, emb_dim)        self.proj = nn.Linear(emb_dim, hidden_dim * 2)        self.lstm1 = nn.LSTM(hidden_dim * 2, hidden_dim,                             batch_first=True, bidirectional=True)        self.lstm2 = nn.LSTM(hidden_dim * 2, hidden_dim,                             batch_first=True, bidirectional=True)        self.layer_w = nn.Parameter(torch.tensor([0.3, 0.3, 0.4]))        self.gamma = nn.Parameter(torch.tensor(1.0))     def forward(self, token_ids):        x = self.proj(self.emb(token_ids))        h1, _ = self.lstm1(x)        h2, _ = self.lstm2(h1)        layers = torch.stack([x, h1, h2], dim=1)        w = torch.softmax(self.layer_w, dim=0)        out = (w.view(1, 3, 1, 1) * layers).sum(dim=1) * self.gamma        return out  def main():    torch.manual_seed(0)    vocab = ["bank", "river", "money", "save", "sit", "fish", "."]    w2i = {w: i for i, w in enumerate(vocab)}     model = SimpleELMo(len(vocab))    s_money = torch.tensor([[w2i["bank"], w2i["save"], w2i["money"], w2i["."]]])    s_river = torch.tensor([[w2i["bank"], w2i["sit"], w2i["river"], w2i["fish"]]])     v_money = model(s_money)[0, 0]    v_river = model(s_river)[0, 0]    d = torch.dist(v_money, v_river).item()    print("untrained: distance = %.4f" % d)     with torch.no_grad():        model.layer_w.copy_(torch.tensor([0.1, 0.3, 0.6]))    v_money = model(s_money)[0, 0]    v_river = model(s_river)[0, 0]    d = torch.dist(v_money, v_river).item()    print("tuned layer weights: distance = %.4f" % d)    print("after real pretraining, the two bank vectors separate clearly")  if __name__ == "__main__":    main()
目的:用 PyTorch 实现一个迷你版 ELMo——双层双向 LSTM 加上层级权重合成,演示同一个词"bank"在不同上下文句子中如何得到不同向量。
  1. self.emb = nn.Embedding(vocab_size, emb_dim)嵌入层,把词 ID 变成稠密向量,对应 ELMo 的初始向量
  2. self.proj = nn.Linear(emb_dim, hidden_dim * 2)投影层,把不同层的向量维度统一,便于后续堆叠
  3. h1, _ = self.lstm1(x)第一层双向 LSTM,从左右两个方向同时读句子
  4. h2, _ = self.lstm2(h1)第二层双向 LSTM,在上一层基础上做更深的语义抽象
  5. layers = torch.stack([x, h1, h2], dim=1)把三层表示叠起来,对应 ELMo 的 R_k 集合
  6. w = torch.softmax(self.layer_w, dim=0)学习三层各自的 softmax 权重
  7. out = (w.view(1, 3, 1, 1) * layers).sum(dim=1) * self.gamma加权合成最终 ELMo 向量
  8. v_money = model(s_money)[0, 0]取出句子 1 中 bank 的上下文向量
  9. d = torch.dist(v_money, v_river).item()计算两个上下文里 bank 向量间的距离

常见误区

误区ELMo 和 BERT 一样,下游任务训练时会反向传播整个预训练模型,把所有参数一起微调。

正解ELMo 采用的是“特征拼接”(feature-based)方案。预训练好的双向 LSTM 在下游任务中处于冻结状态,不参与反向传播。工程师把 ELMo 算出的向量拼接到任务模型的输入/输出端,任务模型只训练自己的参数。真正的“预训练 + 微调”范式要到 GPT 和 BERT 才流行。

为何常见:因为预训练模型通常和“微调”绑定出现,初学者很容易把 ELMo 与后来的 BERT 混为一谈。

误区ELMo 用了双向 LSTM,所以和 BERT 一样能同时看到左右两侧的上下文。

正解ELMo 是前向后向两个独立的 LSTM 先后工作,然后拼接输出。前向只看左边,后向只看右边,两个方向的隐状态没有交互,属于“拼接式双向”;BERT 的 Self-Attention 同时在左右两侧建模,属于“交互式双向”。这也是 BERT 效果通常更强的原因之一。

为何常见:“双向”两个字容易让人忽略实现细节,看到 BiLSTM 就以为和 BERT 等价。

误区ELMo 像 Word2Vec 一样维护一张词向量表,输入词 ID 就能查出一个固定向量。

正解ELMo 没有固定的词向量表。每个词进入句子后,要完整做一次字符 CNN + 双层双向 LSTM 的前向计算,得到“这一次出现”专属的上下文向量。同一个词在不同句子中向量不同,这正是“上下文词嵌入”的本质。

为何常见:人们习惯把“词嵌入”默认成查表操作,而 ELMo 实际是一次神经网络推理。

误区既然是深层模型,就应该只用最后一层 LSTM 输出,前面层是中间产物可以丢弃。

正解原论文实验证明,不同层捕捉不同信息:底层偏词法、中层偏句法、高层偏语义。不同任务对层级信息需求不同,例如 NER 更像句法任务,更偏重中层;问答更像语义任务,更偏重高层。把三层用可学习 softmax 权重加权,往往比单用最后一层更优。

为何常见:深度学习的直觉是“越深层越高级”,但现实中不同任务所需的语言知识层级并不一样。

误区ELMo 既然能区分多义词,那反讽、隐喻、双关等语言现象应该也不在话下。

正解ELMo 的上下文表示来自语言模型目标——它只是学会了“根据上下文猜词”。猜测过程中涌现的语义分辨能力,能消解"bank"级别的多义词,但对需要世界知识和推理的深层语义(如反讽、言外之意)几乎没有帮助。另外 LSTM 对长距离依赖的建模能力有限,句子超过几十个词后信息衰减明显。

为何常见:看到“上下文相关且效果显著提升”后,容易高估模型的语言理解能力。

面试题

Q1. ELMo 的核心创新是?

单选题 · easy

  • A.首次提出 Transformer 架构
  • B.首次用上下文动态生成词向量← 正确答案
  • C.首次将 CNN 用于文本分类
  • D.首次提出注意力机制

答案:B。ELMo 首次把预训练语言模型引入词向量生成,使同一个词在不同句子中得到不同向量(上下文相关)。Transformer 架构和注意力机制都不是 ELMo 提出的,CNN 文本分类也早已有之。

Q2. Word2Vec 与 ELMo 的主要区别是?

单选题 · easy

  • A.Word2Vec 考虑上下文而 ELMo 不考虑
  • B.Word2Vec 向量固定而 ELMo 随语境变化← 正确答案
  • C.Word2Vec 输出句子概率而 ELMo 输出向量
  • D.Word2Vec 是监督学习而 ELMo 是自监督

答案:B。Word2Vec 训练后词向量是静态的,查表即得;ELMo 的向量要经过上下文建模的前向计算,随语境动态变化。C 把两个模型说反了,D 中两者本质上都属于自监督/无监督学习。

Q3. ELMo 中“层级权重”指的是?

单选题 · mid

  • A.对字符 CNN 中各卷积核加权
  • B.对前后向两个 LSTM 输出加权
  • C.对多层 LM 表示做加权求和← 正确答案
  • D.对词表各词出现频率加权

答案:C。ELMo 把第 0 层(词嵌入)、第 1 层、第 2 层 LSTM 输出用 softmax 权重加权求和,权重由下游任务学习。A 是字符 CNN 内部的事,B 的方向不对,D 是统计信息不是层权重。

Q4. 以下关于 ELMo 描述正确的有?

多选题 · mid

  • A.用双向 LSTM 建模语言模型← 正确答案
  • B.输出与上下文相关的动态向量← 正确答案
  • C.通过微调全部参数适配下游
  • D.能有效缓解一词多义问题← 正确答案

答案:ABD。ELMo 用前向后向两个 LSTM 联合建模,输出动态上下文向量,能消解多义词。但 ELMo 是特征拼接而非全量微调,C 错误。注意区分“特征式”与“微调式”两种迁移方式。

Q5. ELMo 后向语言模型如何建模?

单选题 · hard

  • A.从右到左预测前一个词的分布← 正确答案
  • B.从左到右预测后一个词的分布
  • C.随机打乱词序后再做掩码预测
  • D.用双向 Transformer 做并行预测

答案:A。后向 LM 用 LSTM 从句子末尾向开头扫描,条件概率是 p(t_k | t_{k+1}, ……, t_N),即“根据右边的未来词预测当前词”。C 是掩码语言模型思想,D 是 BERT 的做法。

Q6. ELMo 与 BERT 的核心差异是?

单选题 · mid

  • A.ELMo 用 LSTM 而 BERT 用 Transformer← 正确答案
  • B.ELMo 只支持英文而 BERT 支持多语言
  • C.ELMo 不预训练而 BERT 有预训练
  • D.ELMo 输出概率而 BERT 输出向量

答案:A。外层都是“预训练 + 迁移”,但骨干架构一个用双向 LSTM(拼接式双向),一个用 Transformer 的 self-attention(交互式双向)。B、C、D 均不符合事实,两者都预训练且都输出表示向量。

Q7. ELMo 预训练目标函数包括?

多选题 · mid

  • A.最大化前向语言模型的对数概率← 正确答案
  • B.最大化后向语言模型的对数概率← 正确答案
  • C.最小化掩码词的交叉熵损失
  • D.最小化下一句预测的损失

答案:AB。ELMo 的目标是前向和后向两个方向的对数概率之和,本质上都是“预测词”。C 的掩码语言模型和 D 的下一句预测是 BERT 的训练目标,不是 ELMo 的。

Q8. 下游任务中使用 ELMo 的常见方式是?

单选题 · easy

  • A.把 ELMo 向量拼接到任务模型输入← 正确答案
  • B.用 ELMo 完全替换下游任务模型
  • C.直接用 ELMo 向量做余弦相似度分类
  • D.将 ELMo 输出硬编码成固定词表

答案:A。典型做法是冻结 ELMo,把动态向量拼接到下游网络的输入或输出层。B 不成立,C 是词向量相似度分析场景而非任务主流,D 与动态向量的本质矛盾。

Q9. 不同任务为何要学不同层级权重?

单选题 · hard

  • A.因为各任务使用的 GPU 型号不同
  • B.因为各层信息偏好随任务目标而异← 正确答案
  • C.因为每层维度不同需要对齐处理
  • D.因为权重不可训练只能手动枚举

答案:B。ELMo 底层偏词法、中层偏句法、高层偏语义。NER 更像句法任务所以侧重中层,SQuAD 问答更像语义任务所以侧重高层。软权重让任务自适应地组合信息。C 中 ELMo 各层已统一为双向拼接维度,D 显然错误。

Q10. 关于 ELMo 的历史意义说法正确的有?

多选题 · hard

  • A.证明预训练模型可迁移到多种 NLP 任务← 正确答案
  • B.率先采用预训练加微调的完整范式
  • C.推动后续 GPT 和 BERT 等模型发展← 正确答案
  • D.首次实现真正意义上的双向注意力

答案:AC。ELMo 证明了预训练语言模型做特征迁移的有效性,启发了 GPT/BERT。但 ELMo 是“特征拼接”而非微调,真正的“预训练 + 微调”范式由 GPT/BERT 确立;双向注意力是 BERT 的贡献。ELMo 的价值在于开创了可迁移的上下文表示这一方向。