参考:详解深度学习之 Embedding_深度学习embedding_Training.L的博客-CSDN博客
独热编码 one-hot encoding 存在的问题包括如下:
- 大量为 0 的稀疏矩阵;
- 硬编码,特征没有语义信息;
- 特征维度较高,且每个特征都彼此独立,训练所需要的数据量高,容易导致维度灾难;
pytorch中的embedding
在 PyTorch 中,针对词向量有一个专门的层 nn.Embedding ,用来实现词与词向量的映射。nn.Embedding 相当于一个词表,形状为 (num_embedings, embedding_dim) ,其中 num_embedding 表示词表的长度,embedding_dim 表示词向量的维度,如果输入张量中不同词的个数超过词表的长度,就会报数组越界异常。
如果 Embedding 层的输入形状为 NxM(N为batch_size,M是序列的长度),则输出的形状是 N x M x embedding_dim.
注意:输入必须是 LongTensor 类型,可以通过 tensor.long() 方法转成 LongTensor。
import numpy as np
import torch
import torch.nn as nn
import torch.nn.functional as F
word_to_idx = {'girl': 0, 'boy': 1, 'woman': 2, 'man': 3} # 每个单词用一个数字表示
embeds = nn.Embedding(8, 2) # 单词的个数8,2位embedding的维度
inputs = torch.LongTensor([[word_to_idx[key] for key in word_to_idx.keys()]])
inputs = torch.autograd.Variable(inputs)
# 获取Variable对应的embedding,并打印出来
outputs = embeds(inputs)
print(outputs)
print(embeds.weight)
tensor([[[-0.9663, -0.6391], # 0
[-2.2001, 0.7629], # 1
[ 0.1813, -1.1935], # 2
[-0.3214, -0.9004]]], grad_fn=<EmbeddingBackward>) # 3
Parameter containing:
tensor([[-0.9663, -0.6391], # 0
[-2.2001, 0.7629], # 1
[ 0.1813, -1.1935], # 2
[-0.3214, -0.9004], # 3
[-1.7540, 0.0908], # 4
[ 1.1053, -0.8680], # 5
[ 0.2549, 0.2402], # 6
[ 0.9486, -0.7895]], requires_grad=True) # 7
注:Embedding的权重也是可以训练的,既可以采用随机初始化,也可以采用预训练好的词向量初始化。
根据上面的结果我们可以看见,最后每个词向量的表示即是embeds.weights。我们训练模型也是训练的这个词向量的表示。(个人理解,欢迎指正)
觉得某大模型解释(觉得不错就粘上来了):
nn.Embedding
是PyTorch中的一个层(layer),通常用于将整数索引映射到密集的词嵌入(dense word embeddings)。在训练过程中,这些词嵌入通常是需要进行训练的参数。
当你创建一个 nn.Embedding
层时,其中的权重矩阵是一个可学习的参数。这个权重矩阵的行数通常等于词汇表的大小,每一行对应一个词。在训练的过程中,这些权重会被模型自动更新,以便更好地表示输入数据。
下面是一个简单的例子,演示了如何创建一个包含可训练参数的 nn.Embedding
层:
import torch
import torch.nn as nn
# 假设词汇表大小为10,每个词嵌入的维度为3
vocab_size = 10
embedding_dim = 3
# 创建Embedding层
embedding_layer = nn.Embedding(vocab_size, embedding_dim)
# 随机生成一个输入序列,每个元素是一个词的索引
input_indices = torch.tensor([1, 3, 5, 2, 7])
# 将输入序列映射为词嵌入
embedded_input = embedding_layer(input_indices)
# 输出词嵌入
print("embedded_input",embedded_input)
print("weight",embedding_layer.weight)
在pycharm上实验了以下,输出如下:
embedded_input tensor([[-0.0846, -0.4749, -0.9375],
[ 0.5553, -0.5761, 0.3212],
[ 0.6565, -0.9949, 0.0403],
[ 1.2086, -0.5082, 0.5631],
[-0.5930, 0.2317, 0.2993]], grad_fn=<EmbeddingBackward0>)
weight Parameter containing:
tensor([[-0.1824, -0.5277, 0.5130],
[-0.0846, -0.4749, -0.9375], # 1
[ 1.2086, -0.5082, 0.5631], # 2
[ 0.5553, -0.5761, 0.3212], # 3
[ 0.9578, 1.6284, 0.8284],
[ 0.6565, -0.9949, 0.0403], # 5
[-0.5386, -1.2851, -1.1687],
[-0.5930, 0.2317, 0.2993], # 7
[ 0.9817, 0.6104, -0.6185],
[ 0.8134, 0.4338, -1.5441]], requires_grad=True)
可以得到:下面的embedding_layer.weight就是上面经过embedding后的词嵌入表示(embedding_layer.weight即是token的表示),这是一个可学习的权重矩阵,我们在训练的时候,学习的就是这个矩阵。
即:nn.Embedding
的权重矩阵将会在训练中被学习,以便更好地适应模型的任务(更好的表示word/token或者input_id)。