目录
1 nn.Embedding介绍
1.1 nn.Embedding作用
1.2 nn.Embedding函数描述
1.3 nn.Embedding词向量转化
2 nn.Embedding实战
2.1 embedding如何处理文本
2.2 embedding使用示例
2.3 nn.Embedding的可学习性
nn.Embedding是PyTorch中的一个常用模块,其主要作用是将输入的整数序列转换为密集向量表示。在自然语言处理(NLP)任务中,可以将每个单词表示成一个向量,从而方便进行下一步的计算和处理。
nn.Embedding是将输入向量化,定义如下:
torch.nn.Embedding(num_embeddings,
embedding_dim,
padding_idx=None,
max_norm=None,
norm_type=2.0,
scale_grad_by_freq=False,
sparse=False,
_weight=None,
_freeze=False,
device=None,
dtype=None)
参数说明:
- num_embeddings :字典中词的个数
- embedding_dim:embedding的维度
- padding_idx(索引指定填充):如果给定,则遇到padding_idx中的索引,则将其位置填0(0是默认值,事实上随便填充什么值都可以)。
注:embeddings中的值是正态分布N(0,1)中随机取值。
在PyTorch中,nn.Embedding用来实现词与词向量的映射。nn.Embedding具有一个权重(.weight),形状是(num_words, embedding_dim)。例如一共有100个词,每个词用16维向量表征,对应的权重就是一个100×16的矩阵。
Embedding的输入形状N×W,N是batch size,W是序列的长度,输出的形状是N×W×embedding_dim。
Embedding输入必须是LongTensor,FloatTensor需通过tensor.long()方法转成LongTensor。
Embedding的权重是可以训练的,既可以采用随机初始化,也可以采用预训练好的词向量初始化。
在NLP任务中,首先要对文本进行处理,将文本进行编码转换,形成向量表达,embedding处理文本的流程如下:
(1)输入一段文本,中文会先分词(如jieba分词),英文会按照空格提取词
(2)首先将单词转成字典的形式,由于英语中以空格为词的分割,所以可以直接建立词典索引结构。类似于:word2id = {'i' : 1, 'like' : 2, 'you' : 3, 'want' : 4, 'an' : 5, 'apple' : 6} 这样的形式。如果是中文的话,首先进行分词操作。
(3)然后再以句子为list,为每个句子建立索引结构,list [ [ sentence1 ] , [ sentence2 ] ] 。以上面字典的索引来说,最终建立的就是 [ [ 1 , 2 , 3 ] , [ 1 , 4 , 5 , 6 ] ] 。这样长短不一的句子
(4)接下来要进行padding的操作。由于tensor结构中都是等长的,所以要对上面那样的句子做padding操作后再利用 nn.Embedding 来进行词的初始化。padding后的可能是这样的结构
[ [ 1 , 2 , 3, 0 ] , [ 1 , 4 , 5 , 6 ] ] 。其中0作为填充。(注意:由于在NMT任务中肯定存在着填充问题,所以在embedding时一定存在着第三个参数,让某些索引下的值为0,代表无实际意义的填充)
比如有两个句子:
I want a plane
I want to travel to Beijing
将两个句子转化为ID映射:
{I:1,want:2,a:3,plane:4,to:5,travel:6,Beijing:7}
转化成ID表示的两个句子如下:
1,2,3,4
1,2,5,6,5,7
import torch
from torch import nn
# 创建最大词个数为10,每个词用维度为4表示
embedding = nn.Embedding(10, 4)
# 将第一个句子填充0,与第二个句子长度对齐
in_vector = torch.LongTensor([[1, 2, 3, 4, 0, 0], [1, 2, 5, 6, 5, 7]])
out_emb = embedding(in_vector)
print(in_vector.shape)
print((out_emb.shape))
print(out_emb)
print(embedding.weight)
运行结果显示如下:
torch.Size([2, 6])
torch.Size([2, 6, 4])
tensor([[[-0.6642, -0.6263, 1.2333, -0.6055],
[ 0.9950, -0.2912, 1.0008, 0.1202],
[ 1.2501, 0.1923, 0.5791, -1.4586],
[-0.6935, 2.1906, 1.0595, 0.2089],
[ 0.7359, -0.1194, -0.2195, 0.9161],
[ 0.7359, -0.1194, -0.2195, 0.9161]],
[[-0.6642, -0.6263, 1.2333, -0.6055],
[ 0.9950, -0.2912, 1.0008, 0.1202],
[-0.3216, 1.2407, 0.2542, 0.8630],
[ 0.6886, -0.6119, 1.5270, 0.1228],
[-0.3216, 1.2407, 0.2542, 0.8630],
[ 0.0048, 1.8500, 1.4381, 0.3675]]], grad_fn=)
Parameter containing:
tensor([[ 0.7359, -0.1194, -0.2195, 0.9161],
[-0.6642, -0.6263, 1.2333, -0.6055],
[ 0.9950, -0.2912, 1.0008, 0.1202],
[ 1.2501, 0.1923, 0.5791, -1.4586],
[-0.6935, 2.1906, 1.0595, 0.2089],
[-0.3216, 1.2407, 0.2542, 0.8630],
[ 0.6886, -0.6119, 1.5270, 0.1228],
[ 0.0048, 1.8500, 1.4381, 0.3675],
[ 0.3810, -0.7594, -0.1821, 0.5859],
[-1.4029, 1.2243, 0.0374, -1.0549]], requires_grad=True)
注意:
nn.Embedding中的参数并不是一成不变的,它也是会参与梯度下降的。也就是更新模型参数也会更新nn.Embedding的参数,或者说nn.Embedding的参数本身也是模型参数的一部分。
import torch
from torch import nn
# 创建最大词个数为10,每个词用维度为4表示
embedding = nn.Embedding(10, 4)
# 将第一个句子填充0,与第二个句子长度对齐
in_vector = torch.LongTensor([[1, 2, 3, 4, 0, 0], [1, 2, 5, 6, 5, 7]])
optimizer = torch.optim.SGD(embedding.parameters(), lr=0.01)
criteria = nn.MSELoss()
for i in range(1000):
outputs = embedding(torch.LongTensor([1, 2, 3, 4]))
loss = criteria(outputs, torch.ones(4, 4))
loss.backward()
optimizer.step()
optimizer.zero_grad()
print(embedding.weight)
new_output = embedding(in_vector)
print(new_output)
经过1000epochs的训练后,查看新的编码结果,显示如下:
Parameter containing:
tensor([[-0.2475, -1.3436, -0.0449, 0.2093],
[ 0.4831, 0.5887, 1.2278, 1.1106],
[ 1.1809, 0.7451, 0.2049, 1.3053],
[ 0.7369, 1.1276, 1.0066, 0.4399],
[ 1.3064, 0.3979, 0.8753, 0.9410],
[-0.6222, 0.2574, 1.1211, 0.1801],
[-0.5072, 0.2564, 0.5500, 0.3136],
[-1.7473, 0.0504, -0.0633, -0.3138],
[-2.4507, -0.6092, 0.0348, -0.4384],
[ 0.9458, -0.2867, -0.0285, 1.1842]], requires_grad=True)
tensor([[[ 0.4831, 0.5887, 1.2278, 1.1106],
[ 1.1809, 0.7451, 0.2049, 1.3053],
[ 0.7369, 1.1276, 1.0066, 0.4399],
[ 1.3064, 0.3979, 0.8753, 0.9410],
[-0.2475, -1.3436, -0.0449, 0.2093],
[-0.2475, -1.3436, -0.0449, 0.2093]],
[[ 0.4831, 0.5887, 1.2278, 1.1106],
[ 1.1809, 0.7451, 0.2049, 1.3053],
[-0.6222, 0.2574, 1.1211, 0.1801],
[-0.5072, 0.2564, 0.5500, 0.3136],
[-0.6222, 0.2574, 1.1211, 0.1801],
[-1.7473, 0.0504, -0.0633, -0.3138]]], grad_fn=)
权重参数和编码结果都发生了很大变化,所以nn.Embedding在构建模型过程中,可以作为模型的一部分,进行共同训练。