torch.nn.embedding()

作者:top_小酱油
链接:https://www.jianshu.com/p/63e7acc5e890
来源:简书
内容:上述是以RNN为基础解析的

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)

意义

该方法定义了一个简单的存储固定大小的词典的嵌入向量的查找表,意思就是说,这就是一个词典,里面包含了各个单词的向量,如果要访问该查找表,需要你给定一个编号,嵌入层就能返回这个编号对应的嵌入向量,嵌入向量反映了各个编号代表的符号之间的语义关系。

注意这里是定义的查找表! 如果要访问还需要后面的操作! 也就是先定义后操作!

当在访问该查找表的时候:
输入为一个编号列表,输出为对应的符号嵌入向量列表

shape

  • input:(∗),包含提取的编号的intTensor或任意形状的LongTensor。
  • output:(∗,H),其中 * 是输入形状,H = embeddding_dim

参数:

  • Num_embeddings (int) -词典的大小尺寸,比如总共出现5000个词,那就输入5000。此时index为(0-4999)
  • embeddding_dim (int) - 嵌入向量的维度,即用多少维来表示一个符号(单词)。
  • padding_idx (int, optional) -填充id,比如,输入长度为100,但是每次的句子长度并不一样,后面就需要用统一的数字填充,而这里就是指定这个数字,这样,网络在遇到填充id时,就不会计算其与其它符号的相关性。(初始化为0)。
  • max_norm(float,optional)-最大范数,如果嵌入向量的范数超过了这个界限,就要进行再归一化。
  • norm_type(float,optional)-指定利用什么范数计算,并用于对比max_norm,默认为2范数。
  • scale_grad_by_freq(boolean,optional)—— 根据单词在mini-batch中出现的频率,对梯度进行放缩。默认为False.
  • sparse (bool,optional)-若为True,则与权重矩阵相关的梯度转变为稀疏张量。

变量:

~Embedding.weight (Tensor) –形状为 (num_embeddings, embedding_dim) 的学习权重采用标准正态分布N(0,1)进行初始化

NOTE 1:

请记住,只有有限数量的优化器支持稀疏梯度:目前是optim.SGD(CUDA和CPU), optim.SparseAdam (CUDA和CPU)和optim.Adagrad (CPU)

NOTE 2:

当max_norm≠None时,Embedding的前向方法将就地修改权重张量。由于梯度计算所需的张量不能被就地修改,所以在Embedding上执行可微运算。在调用Embedding的前向方法之前,需要克隆Embedding。max_norm不是None时的权重。例如:

n, d, m = 3, 5, 7
embedding = nn.Embedding(n, d, max_norm=True)
W = torch.randn((m, d), requires_grad=True)
idx = torch.tensor([1, 2])
a = embedding.weight.clone() @ W.t()  # weight must be cloned for this to be differentiable
b = embedding(idx) @ W.t()  # modifies weight in-place(就地修改权重)
out = (a.unsqueeze(0) + b.unsqueeze(1))
loss = out.sigmoid().prod()
loss.backward()

整个举例:

实际上,Embedding通过随机初始化建立了词向量层后,建立了一个“二维表”,存储了词典中每个词的词向量。每个mini-batch的训练,都要从词向量表找到mini-batch对应的单词的词向量作为模型的输入放进网络。

>>> # an Embedding module 包含了10个张量,每个张量的大小为3
>>> embedding = nn.Embedding(10, 3)
>>> # a batch 含有两个样本,每个样本长度为4,也就是四个索引,索引是词典中的index序号
>>> input = torch.LongTensor([[1,2,4,5],[4,3,2,9]])
>>> embedding(input)
tensor([[[-0.0251, -1.6902,  0.7172],
         [-0.6431,  0.0748,  0.6969],
         [ 1.4970,  1.3448, -0.9685],
         [-0.3677, -2.7265, -0.1685]],

        [[ 1.4970,  1.3448, -0.9685],
         [ 0.4362, -0.4004,  0.9400],
         [-0.6431,  0.0748,  0.6969],
         [ 0.9124, -2.3616,  1.1151]]])


>>> # example with padding_idx
>>> embedding = nn.Embedding(10, 3, padding_idx=0)
>>> input = torch.LongTensor([[0,2,0,5]])
>>> embedding(input)
tensor([[[ 0.0000,  0.0000,  0.0000],
         [ 0.1535, -2.0309,  0.9315],
         [ 0.0000,  0.0000,  0.0000],
         [-0.1655,  0.9897,  0.0635]]])

>>> # example of changing `pad` vector
>>> padding_idx = 0
>>> embedding = nn.Embedding(3, 3, padding_idx=padding_idx)
>>> embedding.weight
Parameter containing:
tensor([[ 0.0000,  0.0000,  0.0000],
        [-0.7895, -0.7089, -0.0364],
        [ 0.6778,  0.5803,  0.2678]], requires_grad=True)
>>> with torch.no_grad():
...     embedding.weight[padding_idx] = torch.ones(3)
>>> embedding.weight
Parameter containing:
tensor([[ 1.0000,  1.0000,  1.0000],
        [-0.7895, -0.7089, -0.0364],
        [ 0.6778,  0.5803,  0.2678]], requires_grad=True)

一些注意的点

  • nn.embedding的输入只能是编号,不能是隐藏变量,比如one-hot,或者其它,这种情况,可以自己建一个自定义维度的线性网络层,参数训练可以单独训练或者跟随整个网络一起训练(看实验需要)
  • 如果你指定了padding_idx,注意这个padding_idx也是在num_embeddings尺寸内的,比如符号总共有500个,指定了padding_idx,那么num_embeddings应该为501
  • embedding_dim的选择要注意,根据自己的符号数量,举个例子,如果你的词典尺寸是1024,那么极限压缩(用二进制表示)也需要10维,再考虑词性之间的相关性,怎么也要在15-20维左右,虽然embedding是用来降维的,但是>- 也要注意这种极限维度,结合实际情况,合理定义

类方法(ClassMethod)

.from_pretrained(embeddings, freeze=True, padding_idx=None, max_norm=None, norm_type=2.0, scale_grad_by_freq=False, sparse=False)

和上面的使用是类似的,也是定义一个查找表!
从给定的2维FloatTensor创建嵌入实例。

参数

  • embeddings (Tensor)-包含嵌入权值的浮点数。第一个维度作为num_embeddings传递给Embedding,第二个维度作为embeding_dim。
  • freeze (boolean,optional)-如果为True,张量不会在学习过程中得到更新。相当于embedding.weight。requires_grad = False。默认值:真正的
  • padding_idx (int, optional) -如果指定了,则padding_idx上的项不会影响梯度;因此,在训练过程中,padding_idx处的嵌入向量并没有被更新,即它仍然是一个固定的“pad”。
  • max_norm (float,optional)-参见模块初始化文档。
  • norm_type (float,optional)——请参阅模块初始化文档。默认2。
  • scale_grad_by_freq (boolean,optional)-参见模块初始化文档。默认的错误。
  • sparse (bool,optional)-参见模块初始化文档。

举例

>>> # FloatTensor containing pretrained weights
>>> weight = torch.FloatTensor([[1, 2.3, 3], [4, 5.1, 6.3]])
>>> embedding = nn.Embedding.from_pretrained(weight)
>>> # Get embeddings for index 1
>>> input = torch.LongTensor([1])
>>> embedding(input)
tensor([[ 4.0000,  5.1000,  6.3000]])

实际代码举例

if pretrained_word_embedding is None:  #如果没有预训练词典,那么就用第一个
           self.word_embedding = nn.Embedding(config.num_words,
                                              config.word_embedding_dim,
                                              padding_idx=0)
else:  #我们就用预训练的词典
     self.word_embedding = nn.Embedding.from_pretrained(
         pretrained_word_embedding, freeze=False, padding_idx=0)
if pretrained_entity_embedding is None:
     self.entity_embedding = nn.Embedding(config.num_entities,
                                          config.entity_embedding_dim,
                                          padding_idx=0)
else: #实体的嵌入也是一样的,同上
     self.entity_embedding = nn.Embedding.from_pretrained(
         pretrained_entity_embedding, freeze=False, padding_idx=0)
if config.use_context:   #上下文嵌入也是一样的,同上
    if pretrained_context_embedding is None:
        self.context_embedding = nn.Embedding(
            config.num_entities,
            config.entity_embedding_dim,
            padding_idx=0)
    else:
        self.context_embedding = nn.Embedding.from_pretrained(
            pretrained_context_embedding, freeze=False, padding_idx=0)

你可能感兴趣的:(知识图谱源码,知识图谱,知识图谱)