2 词嵌入层¶
学习目标¶
- 知道词嵌入概念
- 掌握PyTorch词嵌入api
我们在进行文本数据处理时,需要将文本进行数据值化,然后进行后续的训练工作。词嵌入层的作用就是将文本转换为向量的。
1. 词嵌入层的使用¶
词嵌入层首先会根据输入的词的数量构建一个词向量矩阵,例如: 我们有 100 个词,每个词希望转换成 128 维度的向量,那么构建的矩阵形状即为: 100*128,输入的每个词都对应了一个该矩阵中的一个向量。
在 PyTorch 中,我们可以使用 nn.Embedding 词嵌入层来实现输入词的向量化。接下来,我们将会学习如何将词转换为词向量,其步骤如下:
- 先将语料进行分词,构建词与索引的映射,我们可以把这个映射叫做词表,词表中每个词都对应了一个唯一的索引;
- 然后使用 nn.Embedding 构建词嵌入矩阵,词索引对应的向量即为该词对应的数值化后的向量表示。
例如,我们的文本数据为: "北京冬奥的进度条已经过半,不少外国运动员在完成自己的比赛后踏上归途。",接下来,我们看下如何使用词嵌入层将其进行转换为向量表示,步骤如下:
- 首先,将文本进行分词;
- 然后,根据词构建词表;
- 最后,使用嵌入层将文本转换为向量表示。
nn.Embedding 对象构建时,最主要有两个参数:
- num_embeddings 表示词的数量
- embedding_dim 表示用多少维的向量来表示每个词
nn.Embedding(num_embeddings=10, embedding_dim=4)
接下来,我们就实现下刚才的需求:
import torch
import torch.nn as nn
import jieba
if __name__ == '__main__':
text = '北京冬奥的进度条已经过半,不少外国运动员在完成自己的比赛后踏上归途。'
# 1. 文本分词
words = jieba.lcut(text)
print('文本分词:', words)
# 2. 构建词表
index_to_word = {}
word_to_index = {}
# 分词去重并保留原来的顺序
unique_words = list(set(words))
for idx, word in enumerate(unique_words):
index_to_word[idx] = word
word_to_index[word] = idx
# 3. 构建词嵌入层
# num_embeddings: 表示词表词的总数量
# embedding_dim: 表示词嵌入的维度
embed = nn.Embedding(num_embeddings=len(index_to_word), embedding_dim=4)
# 4. 文本转换为词向量表示
print('-' * 82)
for word in words:
# 获得词对应的索引
idx = word_to_index[word]
# 获得词嵌入向量
word_vec = embed(torch.tensor(idx))
print('%3s\t' % word, word_vec)
文本分词: ['北京', '冬奥', '的', '进度条', '已经', '过半', ',', '不少', '外国', '运动员', '在', '完成', '自己', '的', '比赛', '后', '踏上', '归途', '。']
----------------------------------------------------------------------------------
北京 tensor([-0.9270, -0.2379, -0.6142, -1.4764], grad_fn=<EmbeddingBackward>)
冬奥 tensor([ 0.3541, -0.4493, 0.7205, 0.1818], grad_fn=<EmbeddingBackward>)
的 tensor([-0.4832, -1.4191, 0.6283, 0.0977], grad_fn=<EmbeddingBackward>)
进度条 tensor([ 1.4518, -0.3859, -0.6866, 1.1921], grad_fn=<EmbeddingBackward>)
已经 tensor([ 0.3793, 1.6623, -0.2279, -0.2272], grad_fn=<EmbeddingBackward>)
过半 tensor([ 0.0732, 1.4832, -0.7802, 0.6884], grad_fn=<EmbeddingBackward>)
, tensor([ 0.6126, 1.0175, -0.4427, 0.6719], grad_fn=<EmbeddingBackward>)
不少 tensor([ 1.0787, -0.2942, -1.0300, -0.6026], grad_fn=<EmbeddingBackward>)
外国 tensor([-0.0484, -0.1542, 1.0033, -1.2332], grad_fn=<EmbeddingBackward>)
运动员 tensor([-1.3133, 0.3807, 0.3957, 1.1283], grad_fn=<EmbeddingBackward>)
在 tensor([ 0.0146, -1.7078, -0.9399, 1.5368], grad_fn=<EmbeddingBackward>)
完成 tensor([-0.1084, -0.0734, -0.1800, -0.5065], grad_fn=<EmbeddingBackward>)
自己 tensor([ 0.8480, -0.4750, -0.1357, 0.4134], grad_fn=<EmbeddingBackward>)
的 tensor([-0.4832, -1.4191, 0.6283, 0.0977], grad_fn=<EmbeddingBackward>)
比赛 tensor([0.0928, 0.8925, 1.1197, 2.5525], grad_fn=<EmbeddingBackward>)
后 tensor([ 0.8835, 0.7304, 1.3754, -1.7842], grad_fn=<EmbeddingBackward>)
踏上 tensor([ 1.0809, -0.3135, 0.6346, 0.3923], grad_fn=<EmbeddingBackward>)
归途 tensor([ 0.1834, -1.2411, -0.9244, -0.0265], grad_fn=<EmbeddingBackward>)
。 tensor([ 0.0290, 0.1881, -1.3138, 0.6514], grad_fn=<EmbeddingBackward>)
2. 关于词嵌入层的思考¶
我们的词嵌入层默认使用的是均值为 0,标准差为 1 的正态分布进行初始化,也可以理解为是随机初始化。有些同学可能就想,这个用来表示词的文本真的能够表达出词的含义吗?
- nn.Embedding 中对每个词的向量表示都是随机生成的
- 当一个词输入进来之后,会使用随机产生的向量来表示该词
- 该词向量参与到下游任务的计算
- 下游任务计算之后,会和目标结果进行对比产生损失
- 接下来,通过反向传播更新所有的网络参数,这里的参数就包括了 nn.Embedding 中的词向量表示
这样通过反复的前向计算、反向传播、参数更新,最终我们每个词的向量表示就会变得更合理。
3. 小节¶
本小节主要讲解了在自然语言处理任务中,经常使用的词嵌入层的使用。它的主要作用就是将输入的词映射为词向量,便于在网络模型中进行计算。
这里需要注意的是, 词嵌入层中的向量表示是可学习的,并不是固定不变的。