Word2Vec 应用详解基于4_word2vec_apply.ipynb的逐节讲解用最通俗的方式说清楚每个环节。目录词嵌入层Embedding是什么什么是 nn.Embedding把 Word2Vec 加载到 Embedding 层完整的 NLP 处理流程OOV未登录词问题1. 词嵌入层Embedding是什么核心思想计算机不认识地铁这个词只认识数字。所以我们需要给每个词一个唯一的编号ID然后把 ID 转换成一个稠密向量一串有意义的数字。打个比方词表就像一个字典 我 → ID: 0 → 向量: [0.1, 0.3, -0.2, ...] 100个数字 喜欢 → ID: 1 → 向量: [0.5, -0.1, 0.7, ...] 100个数字 地铁 → ID: 2 → 向量: [-0.3, 0.8, 0.2, ...] 100个数字这些向量不是随便的数字而是有语义的——语义相近的词向量也相近。比如地铁和公交的向量在空间中距离很近地铁和图书馆的距离就远。Embedding 层本质上就是一张查表输入词 ID比如 2 → 去查 Embedding 表的第 2 行 → 输出100 维向量这张表刚开始是随机初始化的全是乱数需要训练才能变得有意义。2. 什么是 nn.Embeddingembeddingnn.Embedding(num_embeddings10000,# 词表大小一共能查 10000 个不同的词embedding_dim300,# 向量维度每个词用 300 个数字表示)参数详解参数含义类比num_embeddings10000词表大小即最多支持 10000 个不同的词字典里有 10000 个词条embedding_dim300每个词用 300 维向量表示每个词条用 300 个特征描述权重矩阵的形状embedding.weight.shape → torch.Size([10000, 300])这是一个10000 行 × 300 列的矩阵。每一行对应一个词的 300 维向量。[第0行: 词ID0的向量 → 0.1, 0.3, -0.2, ...] [第1行: 词ID1的向量 → 0.5, -0.1, 0.7, ...] W [第2行: 词ID2的向量 → -0.3, 0.8, 0.2, ...] [ ... ] [第9999行: 词ID9999的向量 → ... ]前向传播过程输入: ID 2 ↓ 去 W 矩阵查第 2 行 ↓ 输出: [-0.3, 0.8, 0.2, ...] (300维向量)关键理解nn.Embedding没有可学习的计算它只是一个查表操作训练过程中这个表的每一行每个词的向量会通过反向传播不断更新训练结束后语义相近的词在向量空间中距离更近3. 把 Word2Vec 加载到 Embedding 层为什么要这么做之前 nn.Embedding 的权重是随机初始化的——这相当于让模型从零开始学词义效率很低。如果我们直接用 Word2Vec 已经训练好的词向量来初始化 Embedding 层模型就**天生知道地铁和公交是近义词**不需要从头学起。这就是迁移学习的思想。代码流程# 第1步加载之前训练好的 Word2Vec 模型wv_modelKeyedVectors.load_word2vec_format(data/word2vec.model)# 第2步获取词向量矩阵34576个词每个100维embedding_matrixwv_model.vectors# shape: (34576, 100)# 第3步用预训练权重创建 Embedding 层embeddingnn.Embedding.from_pretrained(embeddingstorch.tensor(embedding_matrix),# Word2Vec 训练好的权重freezeFalse,# 不冻结允许后续微调)freezeFalse 是什么意思参数含义类比freezeTrue冻结词向量不参与训练把 Word2Vec 当作固定的查表工具后面的模型只能用它不能改它freezeFalse微调词向量参与训练先用 Word2Vec 打好基础然后在具体任务中继续优化词向量选哪个数据量小→freezeTrue防止过拟合保持预训练知识数据量大→freezeFalse让词向量适应具体任务效果更好4. 完整的 NLP 处理流程从原始文本到模型能理解的数值化表示需要经过 4 个步骤原始文本 → 分词 → 查 ID → 词嵌入 → 词向量序列逐步拆解第1步分词text我喜欢乘坐地铁tokensjieba.lcut(text)# 结果: [我, 喜欢, 乘坐, 地铁]把一句完整的话切分成独立的词。中文没有空格所以需要 jieba 这样的分词工具。第2步词 → IDword2idwv_model.key_to_index ids[word2id[token]fortokenintokens]# 结果: [12, 345, 678, 901]每个词在词表中都有一个对应的 ID。这一步把人类可读的文字变成了数字。第3步ID 列表 → 张量inputtorch.tensor(ids)# 结果: tensor([12, 345, 678, 901])shape: (4,)PyTorch 只能处理张量Tensor不能直接处理 Python 列表。所以需要转换。第4步ID → 词向量vectorsembedding(input)# 结果: shape (4, 100)每个 ID 查 Embedding 表得到对应的 100 维向量。4 个词 → 4 个向量每个 100 维。最终结果输入文本: 我喜欢乘坐地铁 ↓ [ 我 ] → [0.1, 0.3, -0.2, ...] (100维) [ 喜欢] → [0.5, -0.1, 0.7, ...] (100维) [ 乘坐] → [-0.2, 0.6, 0.1, ...] (100维) [ 地铁] → [-0.3, 0.8, 0.2, ...] (100维)这组(4, 100)的张量就是 RNN/LSTM/Transformer 可以输入并处理的数值化表示。5. OOV未登录词问题什么是 OOVOOV Out-of-Vocabulary意思是词表之外的词。问题场景text我喜欢乘坐宇宙飞船# 宇宙飞船 这个词可能在之前的训练语料中没出现过# word2id[宇宙飞船] → ❌ KeyError!为什么会出现 OOVWord2Vec 训练时只学习了语料中出现的词。如果语料里没有宇宙飞船词表中就不会有这个词。现实中的文本永远会出现新词、生僻词、专业术语。解决方案UNK 标记思路给所有未知词一个统一的垃圾桶——UNK 标记。第1步在词表最前面插入 UNKunk_tokenUNKid2word[unk_token]wv_model.index_to_key# 新词表: [UNK, 的, 了, 我, 地铁, ...]# ↑ ID0 ↑ ID1 ↑ ID2 ...第2步重建 Embedding 层# 创建一个 1 行 100 列的全零向量给 UNKunk_vectortorch.zeros((1,100))# 把 UNK 向量拼接到原始词向量矩阵的最前面embedding_matrixtorch.cat([unk_vector,torch.tensor(wv_model.vectors)])# 新矩阵: (34577, 100) — 比原来多了 1 行UNK# 创建新的 Embedding 层embeddingnn.Embedding.from_pretrained(embedding_matrix,freezeFalse)拼接后的 Embedding 表ID0: UNK → [0, 0, 0, ...] (全零初始值后续可训练) ID1: 我 → [0.1, 0.3, ...] (Word2Vec 预训练) ID2: 喜欢→ [0.5, -0.1, ...] (Word2Vec 预训练) ...第3步编码时用 UNK 兜底# .get(key, default)如果 key 不存在返回默认值ids[word2id.get(token,word2id[unk_token])fortokenintokens]# 如果 token宇宙飞船 不在词表中# 返回 word2id[UNK] 0第4步前向传播结果输入: 我喜欢乘坐宇宙飞船 ↓ 分词: [我, 喜欢, 乘坐, 宇宙飞船] ↓ ID: [1, 2, 3, 0] ← 宇宙飞船 → ID0 (UNK) ↓ 向量: [预训练向量, 预训练向量, 预训练向量, 全零向量] ↑ 宇宙飞船是未知词 所以暂时是零向量UNK 向量会一直是零吗不会。因为freezeFalse在后续任务训练中UNK 向量会通过反向传播自动学习更新逐渐从不合理的零向量变成一个合理的向量。核心要点总结概念一句话理解Embedding 层一张查表词 ID 进去词向量出来预训练加载用 Word2Vec 训练好的权重初始化 Embedding而不是随机初始化freezeFalse允许词向量在后续任务中继续微调优化OOV 问题遇到词表中没有的词怎么办UNK 方案给所有未知词分配同一个特殊 ID用一个可训练的向量表示它们完整流程图┌─────────────────────────────────────────────────────────────────────┐ │ 完整 NLP 处理 Pipeline │ └─────────────────────────────────────────────────────────────────────┘ 原始文本: 我喜欢乘坐地铁 │ ▼ jieba.lcut() 分词结果: [我, 喜欢, 乘坐, 地铁] │ ▼ key_to_index[] 词ID列表: [12, 345, 678, 901] │ ▼ torch.tensor() PyTorch张量: tensor([12, 345, 678, 901]) │ ▼ embedding(input) 词向量序列: shape (4, 100) │ ▼ 输入下游模型 RNN / LSTM / GRU / Transformer ... │ ▼ 最终输出 情感分类 / 翻译 / 命名实体识别 ...
NLP系列之Word2Vec 应用详解
发布时间:2026/5/20 1:31:33
Word2Vec 应用详解基于4_word2vec_apply.ipynb的逐节讲解用最通俗的方式说清楚每个环节。目录词嵌入层Embedding是什么什么是 nn.Embedding把 Word2Vec 加载到 Embedding 层完整的 NLP 处理流程OOV未登录词问题1. 词嵌入层Embedding是什么核心思想计算机不认识地铁这个词只认识数字。所以我们需要给每个词一个唯一的编号ID然后把 ID 转换成一个稠密向量一串有意义的数字。打个比方词表就像一个字典 我 → ID: 0 → 向量: [0.1, 0.3, -0.2, ...] 100个数字 喜欢 → ID: 1 → 向量: [0.5, -0.1, 0.7, ...] 100个数字 地铁 → ID: 2 → 向量: [-0.3, 0.8, 0.2, ...] 100个数字这些向量不是随便的数字而是有语义的——语义相近的词向量也相近。比如地铁和公交的向量在空间中距离很近地铁和图书馆的距离就远。Embedding 层本质上就是一张查表输入词 ID比如 2 → 去查 Embedding 表的第 2 行 → 输出100 维向量这张表刚开始是随机初始化的全是乱数需要训练才能变得有意义。2. 什么是 nn.Embeddingembeddingnn.Embedding(num_embeddings10000,# 词表大小一共能查 10000 个不同的词embedding_dim300,# 向量维度每个词用 300 个数字表示)参数详解参数含义类比num_embeddings10000词表大小即最多支持 10000 个不同的词字典里有 10000 个词条embedding_dim300每个词用 300 维向量表示每个词条用 300 个特征描述权重矩阵的形状embedding.weight.shape → torch.Size([10000, 300])这是一个10000 行 × 300 列的矩阵。每一行对应一个词的 300 维向量。[第0行: 词ID0的向量 → 0.1, 0.3, -0.2, ...] [第1行: 词ID1的向量 → 0.5, -0.1, 0.7, ...] W [第2行: 词ID2的向量 → -0.3, 0.8, 0.2, ...] [ ... ] [第9999行: 词ID9999的向量 → ... ]前向传播过程输入: ID 2 ↓ 去 W 矩阵查第 2 行 ↓ 输出: [-0.3, 0.8, 0.2, ...] (300维向量)关键理解nn.Embedding没有可学习的计算它只是一个查表操作训练过程中这个表的每一行每个词的向量会通过反向传播不断更新训练结束后语义相近的词在向量空间中距离更近3. 把 Word2Vec 加载到 Embedding 层为什么要这么做之前 nn.Embedding 的权重是随机初始化的——这相当于让模型从零开始学词义效率很低。如果我们直接用 Word2Vec 已经训练好的词向量来初始化 Embedding 层模型就**天生知道地铁和公交是近义词**不需要从头学起。这就是迁移学习的思想。代码流程# 第1步加载之前训练好的 Word2Vec 模型wv_modelKeyedVectors.load_word2vec_format(data/word2vec.model)# 第2步获取词向量矩阵34576个词每个100维embedding_matrixwv_model.vectors# shape: (34576, 100)# 第3步用预训练权重创建 Embedding 层embeddingnn.Embedding.from_pretrained(embeddingstorch.tensor(embedding_matrix),# Word2Vec 训练好的权重freezeFalse,# 不冻结允许后续微调)freezeFalse 是什么意思参数含义类比freezeTrue冻结词向量不参与训练把 Word2Vec 当作固定的查表工具后面的模型只能用它不能改它freezeFalse微调词向量参与训练先用 Word2Vec 打好基础然后在具体任务中继续优化词向量选哪个数据量小→freezeTrue防止过拟合保持预训练知识数据量大→freezeFalse让词向量适应具体任务效果更好4. 完整的 NLP 处理流程从原始文本到模型能理解的数值化表示需要经过 4 个步骤原始文本 → 分词 → 查 ID → 词嵌入 → 词向量序列逐步拆解第1步分词text我喜欢乘坐地铁tokensjieba.lcut(text)# 结果: [我, 喜欢, 乘坐, 地铁]把一句完整的话切分成独立的词。中文没有空格所以需要 jieba 这样的分词工具。第2步词 → IDword2idwv_model.key_to_index ids[word2id[token]fortokenintokens]# 结果: [12, 345, 678, 901]每个词在词表中都有一个对应的 ID。这一步把人类可读的文字变成了数字。第3步ID 列表 → 张量inputtorch.tensor(ids)# 结果: tensor([12, 345, 678, 901])shape: (4,)PyTorch 只能处理张量Tensor不能直接处理 Python 列表。所以需要转换。第4步ID → 词向量vectorsembedding(input)# 结果: shape (4, 100)每个 ID 查 Embedding 表得到对应的 100 维向量。4 个词 → 4 个向量每个 100 维。最终结果输入文本: 我喜欢乘坐地铁 ↓ [ 我 ] → [0.1, 0.3, -0.2, ...] (100维) [ 喜欢] → [0.5, -0.1, 0.7, ...] (100维) [ 乘坐] → [-0.2, 0.6, 0.1, ...] (100维) [ 地铁] → [-0.3, 0.8, 0.2, ...] (100维)这组(4, 100)的张量就是 RNN/LSTM/Transformer 可以输入并处理的数值化表示。5. OOV未登录词问题什么是 OOVOOV Out-of-Vocabulary意思是词表之外的词。问题场景text我喜欢乘坐宇宙飞船# 宇宙飞船 这个词可能在之前的训练语料中没出现过# word2id[宇宙飞船] → ❌ KeyError!为什么会出现 OOVWord2Vec 训练时只学习了语料中出现的词。如果语料里没有宇宙飞船词表中就不会有这个词。现实中的文本永远会出现新词、生僻词、专业术语。解决方案UNK 标记思路给所有未知词一个统一的垃圾桶——UNK 标记。第1步在词表最前面插入 UNKunk_tokenUNKid2word[unk_token]wv_model.index_to_key# 新词表: [UNK, 的, 了, 我, 地铁, ...]# ↑ ID0 ↑ ID1 ↑ ID2 ...第2步重建 Embedding 层# 创建一个 1 行 100 列的全零向量给 UNKunk_vectortorch.zeros((1,100))# 把 UNK 向量拼接到原始词向量矩阵的最前面embedding_matrixtorch.cat([unk_vector,torch.tensor(wv_model.vectors)])# 新矩阵: (34577, 100) — 比原来多了 1 行UNK# 创建新的 Embedding 层embeddingnn.Embedding.from_pretrained(embedding_matrix,freezeFalse)拼接后的 Embedding 表ID0: UNK → [0, 0, 0, ...] (全零初始值后续可训练) ID1: 我 → [0.1, 0.3, ...] (Word2Vec 预训练) ID2: 喜欢→ [0.5, -0.1, ...] (Word2Vec 预训练) ...第3步编码时用 UNK 兜底# .get(key, default)如果 key 不存在返回默认值ids[word2id.get(token,word2id[unk_token])fortokenintokens]# 如果 token宇宙飞船 不在词表中# 返回 word2id[UNK] 0第4步前向传播结果输入: 我喜欢乘坐宇宙飞船 ↓ 分词: [我, 喜欢, 乘坐, 宇宙飞船] ↓ ID: [1, 2, 3, 0] ← 宇宙飞船 → ID0 (UNK) ↓ 向量: [预训练向量, 预训练向量, 预训练向量, 全零向量] ↑ 宇宙飞船是未知词 所以暂时是零向量UNK 向量会一直是零吗不会。因为freezeFalse在后续任务训练中UNK 向量会通过反向传播自动学习更新逐渐从不合理的零向量变成一个合理的向量。核心要点总结概念一句话理解Embedding 层一张查表词 ID 进去词向量出来预训练加载用 Word2Vec 训练好的权重初始化 Embedding而不是随机初始化freezeFalse允许词向量在后续任务中继续微调优化OOV 问题遇到词表中没有的词怎么办UNK 方案给所有未知词分配同一个特殊 ID用一个可训练的向量表示它们完整流程图┌─────────────────────────────────────────────────────────────────────┐ │ 完整 NLP 处理 Pipeline │ └─────────────────────────────────────────────────────────────────────┘ 原始文本: 我喜欢乘坐地铁 │ ▼ jieba.lcut() 分词结果: [我, 喜欢, 乘坐, 地铁] │ ▼ key_to_index[] 词ID列表: [12, 345, 678, 901] │ ▼ torch.tensor() PyTorch张量: tensor([12, 345, 678, 901]) │ ▼ embedding(input) 词向量序列: shape (4, 100) │ ▼ 输入下游模型 RNN / LSTM / GRU / Transformer ... │ ▼ 最终输出 情感分类 / 翻译 / 命名实体识别 ...