pytorch中nn.Embedding原理及使用
输入是什么样子,输出是什么样子?nn.Embedding(),用来实现词与词向量的映射,通俗来讲就是将文字转换为一串数字,作为训练的一层,随模型训练得到适合的词向量。下面会通过实例来解释,比较直观,看到最后。格式:torch.nn.Embedding(num_embeddings, embedding_dim, padding_idx=None,max_norm=None,norm_type=2.
输入是什么样子,输出是什么样子?
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)
参数:
num_embeddings (python:int) – 词典的大小尺寸,比如总共出现5000个词,那就输入5000。此时index为(0-4999)
embedding_dim (python:int) – 嵌入向量的维度,即用多少维来表示一个符号。
padding_idx (python:int, optional) – 填充id,比如,输入长度为100,但是每次的句子长度并不一样,后面就需要用统一的数字填充,而这里就是指定这个数字,这样,网络在遇到填充id时,就不会计算其与其它符号的相关性。(初始化为0)
max_norm (python:float, optional) – 最大范数,如果嵌入向量的范数超过了这个界限,就要进行再归一化。
norm_type (python:float, optional) – 指定利用什么范数计算,并用于对比max_norm,默认为2范数。
scale_grad_by_freq (boolean, optional) – 根据单词在mini-batch中出现的频率,对梯度进行放缩。默认为False.
sparse (bool, optional) – 若为True,则与权重矩阵相关的梯度转变为稀疏张量。
举个栗子:
一个mini-batch如下:
['I am a boy.','How are you?','I am very lucky.']
mini-batch有3个句子,即batch_size=3
这种句子是不能直接输入网络的,我们需要将句子标准化,即:大写转小写,标点分离。经处理后,mini-batch变为:
[['i','am','a','boy','.'],['how','are','you','?'],['i','am','very','lucky','.']]
将上面的三个list按单词数从多到少排列。标点也算单词
batch = [['i','am','a','boy','.'],['i','am','very','lucky','.'],['how','are','you','?']]
可见,每个句子的长度,即每个内层list的元素数为:5,5,4。这个长度记录下。
lens = [5,5,4]
之后,为了能够处理,将batch的单词表示转为在词典中的index序号,这就是word2id的作用。转换过程很简单,假设转换之后的结果如下所示,当然这些序号是我编的。
batch = [[3,6,5,6,7],[6,4,7,9,5],[4,5,8,7]]
同时,每个句子结尾要加EOS,假设EOS在词典中的index是1。
batch = [[3,6,5,6,7,1],[6,4,7,9,5,1],[4,5,8,7,1]]
那么长度要更新:
lens = [6,6,5]
很显然,这个mini-batch中的句子长度不一致!所以为了规整的处理,对长度不足的句子,进行填充。填充PAD假设序号是2,填充之后为:
batch = [[3,6,5,6,7,1],[6,4,7,9,5,1],[4,5,8,7,1,2]]
这样就可以直接取词向量训练了吗?
不能!上面batch有3个样例,RNN的每一步要输入每个样例的一个单词,一次输入batch_size个样例,所以batch要按list外层是时间步数(即序列长度),list内层是batch_size排列。即batch的维度应该是:
[seq_len,batch_size]
seq_len即为句子长度
怎么变换呢?变换方法可以是:使用itertools模块的zip_longest函数。而且,使用这个函数,连填充这一步都可以省略,因为这个函数可以实现填充!
batch = list(itertools.zip_longest(batch,fillvalue=PAD))
# fillvalue就是要填充的值,强制转成list
经变换,结果应该是:
batch = [[3,6,4],[6,4,5],[5,7,8],[6,9,7],[7,5,1],[1,1,2]]
即shape = [6,3] # [seq_len,batch_size]
记得我们还记录了一个lens:
lens = [6,6,5]
batch还要转成LongTensor:
batch=torch.LongTensor(batch)
这里的batch就是词向量层的输入。
词向量层的输出是什么样的?
好了,现在使用建立了的embedding直接通过batch取词向量了,如:
embed = torch.nn.Embedding(n_vocabulary,embedding_size)
embed_batch = embed (batch)
假设词向量维度是6,结果是:
tensor([[[-0.2699, 0.7401, -0.8000, 0.0472, 0.9032, -0.0902],
[-0.2675, 1.8021, 1.4966, 0.6988, 1.4770, 1.1235],
[ 0.1146, -0.8077, -1.4957, -1.5407, 0.3755, -0.6805]],
[[-0.2675, 1.8021, 1.4966, 0.6988, 1.4770, 1.1235],
[ 0.1146, -0.8077, -1.4957, -1.5407, 0.3755, -0.6805],
[-0.0387, 0.8401, 1.6871, 0.3057, -0.8248, -0.1326]],
[[-0.0387, 0.8401, 1.6871, 0.3057, -0.8248, -0.1326],
[-0.3745, -1.9178, -0.2928, 0.6510, 0.9621, -1.3871],
[-0.6739, 0.3931, 0.1464, 1.4965, -0.9210, -0.0995]],
[[-0.2675, 1.8021, 1.4966, 0.6988, 1.4770, 1.1235],
[-0.7411, 0.7948, -1.5864, 0.1176, 0.0789, -0.3376],
[-0.3745, -1.9178, -0.2928, 0.6510, 0.9621, -1.3871]],
[[-0.3745, -1.9178, -0.2928, 0.6510, 0.9621, -1.3871],
[-0.0387, 0.8401, 1.6871, 0.3057, -0.8248, -0.1326],
[ 0.2837, 0.5629, 1.0398, 2.0679, -1.0122, -0.2714]],
[[ 0.2837, 0.5629, 1.0398, 2.0679, -1.0122, -0.2714],
[ 0.2837, 0.5629, 1.0398, 2.0679, -1.0122, -0.2714],
[ 0.2242, -1.2474, 0.3882, 0.2814, -0.4796, 0.3732]]],
grad_fn=<EmbeddingBackward>)
维度的前两维和前面讲的是一致的。可见多了一个第三维,这就是词向量维度。上面的输出可以理解为每一个词都对应了一个词向量,比如上面的每个输出对应一个六维的向量!所以,Embedding层的输出是:
[seq_len,batch_size,embedding_size]
参考:
https://www.jianshu.com/p/63e7acc5e890
更多推荐
所有评论(0)