在 NLP 领域,可以使用 Pytorch 的 torch.nn.Embeding() 类对数据进行词嵌入预处理。关于词嵌入的解释这里就不做解释咯,不明白的阔以先出门左拐找百度。
重点说下这个 Embeding 类怎么用的。其定义如下:
(class) Embedding(num_embeddings: int, embedding_dim: int, padding_idx: int | None = None, ...)
我这里只显示了三个参数:num_embeddings、embedding_dim、padding_idx,其他的实在不常用就忽略了。这三个参数里最常用的只有前两个参数,也是最容易理解的两个参数,先看下源码中的解释:
num_embeddings (int): size of the dictionary of embeddings
embedding_dim (int): the size of each embedding vector
容易看出,num_embeddings 表示字典的大小,embedding_dim 表示目标词向量的长度。
重点说下第三个参数:padding_idx
这个参数网上的解释比较少,源码中的解释是这样的:
padding_idx (int, optional):
If specified, the entries at :attr:`padding_idx` do not contribute to the gradient;
therefore, the embedding vector at :attr:`padding_idx` is not updated during training,
i.e. it remains as a fixed "pad". For a newly constructed Embedding,
the embedding vector at :attr:`padding_idx` will default to all zeros,
but can be updated to another value to be used as the padding vector.
就是说,这是一个索引值,整数类型。如果这个索引值被设置为了某个整数 padding_idx ,则该索引位置的参数不会随着训练而更新梯度也就一直固定了,进一步的,该位置对生成的词向量的作用是固定的。一般来说会默认把这个索引位置的参数设置为 0 ,也可以自定义为其他值。
一般来说,在词嵌入生成词向量的过程中,这个位置经常用在 PAD(词填充符号)类型的映射上。
举个例子来捋一下:
先看一个一般的例子,没用到 padding_idx 参数。
假设词汇表中共有 10 个词,想把每个词映射为一个 3 维的词向量,输入是一个 (2, 4) 的tensor,姑且认为 batchsize 为 2,句子长度都是 4。词嵌入程序如下:
import torch
embedding = torch.nn.Embedding(10, 3)
input = torch.autograd.Variable(torch.LongTensor([[1,2,3,4],[5,6,7,8]])) # 原始输入
print(input.size()) # 原始输入的size:torch.Size([2, 4])
wod2vec = embedding(input) # 词嵌入
print(wod2vec.size()) # 映射为词向量之后的size : torch.Size([2, 4, 3])
print(wod2vec )
print('\n')
print(embedding.weight)
可以打印出词嵌入的结果 wod2vec 以及 词嵌入矩阵的参数 embedding.weight 分别如下:
tensor([[[ 0.8613, 2.2960, -0.1203],
[-0.1843, -0.2376, -0.7213],
[-0.3100, 0.2543, 0.7514],
[-0.5028, 1.1739, 0.3313]],
[[-0.3697, 0.2790, 0.2608],
[-0.8860, -0.7625, 1.4434],
[ 1.1633, -1.4302, -0.9770],
[-0.1257, -1.6048, 1.1272]]], grad_fn=)
Parameter containing:
tensor([[ 1.1076, 0.6360, -0.6193],
[ 0.8613, 2.2960, -0.1203],
[-0.1843, -0.2376, -0.7213],
[-0.3100, 0.2543, 0.7514],
[-0.5028, 1.1739, 0.3313],
[-0.3697, 0.2790, 0.2608],
[-0.8860, -0.7625, 1.4434],
[ 1.1633, -1.4302, -0.9770],
[-0.1257, -1.6048, 1.1272],
[-0.0954, -0.8601, -0.4030]], requires_grad=True)
容易理解,参数矩阵是一个 (10, 3) 的矩阵。每一行都代表对一个特定字符(或单词)的映射,为了对句子有一个很好地表征,目前情况下,这个参数矩阵在训练过程中是随着梯度不断更新的。
那么问题来了:在数据预处理过程中我们会吧句子设置为固定的长度,当一个句子的长度不够时就需要进行填充处理,假设填充的字符设置为
import torch
embedding = torch.nn.Embedding(10, 3, padding_idx = 0)
input = torch.autograd.Variable(torch.LongTensor([[1,2,3,4],[5,6,7,8]])) # 原始输入
wod2vec = embedding(input) # 词嵌入
print(embedding.weight)
""" 输出 """
tensor([[ 0.0000, 0.0000, 0.0000],
[-0.7544, 0.2482, -0.8668],
[-0.7597, -0.7937, -0.2294],
[-1.4075, 0.5869, -0.3124],
[ 1.7170, 0.0689, 0.3069],
[ 0.5717, -2.0616, -0.4522],
[ 0.8203, -0.7685, 0.2621],
[ 1.8317, 0.9464, -2.0914],
[ 1.1449, -0.2370, -0.2006],
[ 0.2089, 0.2276, -1.4627]], requires_grad=True)
可以看出,权重矩阵中代表
src_pad_idx = data['vocab']['src'].vocab.stoi['']
stoi 的作用就是 返回字典中的字符(单词)对应的索引,另外可能还会遇到 itos,就是返回某个索引对应的字典值。
我不是搞 NLP 的,只是用到了相关的知识,学科交叉嘛,不寒掺,点到为止咯。
顺便插播一个笔记:NLP 中的几种常用术语及其意义
PAD:就是 padding ,与 CV 中的 padding 表达的意思类似,将不同的句子处理为相同长度,通常会在前或后补齐,用 pad 填充句子长度不足的部分。在 NLP 训练的过程中, 我们会将数据按 Batch 输入, 但是这些 Batch 必须拥有相同的长度。
UNK:即 unknow ,代表词汇表里不存在的字符, 通常是一些低频词, 或者低频字, 或者特殊符号。
BOS:Begin Of Sentence,代表序列的开始。
EOS:End Of Sentence,代表序列的结束。