当前位置: 代码迷 >> 综合 >> nn.Embedding 学习笔记
  详细解决方案

nn.Embedding 学习笔记

热度:9   发布时间:2024-01-09 05:44:20.0

文章目录

  • 1. nn.Embedding
    • 1.1 说明
    • 1.2 代码-随机生成表
    • 1.3 代码-自定义表
  • 2. nn.EmbeddingBag
    • 2.1 代码
  • 3. 小结

1. nn.Embedding

1.1 说明

torch.nn.Embedding官网链接

  • 作用:一个简单的查找表,存储固定字典和大小的嵌入。这个模块通常用于存储单词嵌入并使用索引检索它们。模块的输入是一个索引列表,输出是相应的单词嵌入。
  • 函数:embeddings = nn.Embedding(10, 3,padding_idx=2):表示创建一个行数为10,列数为3的表,其中第2行全部填充为0。
class 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, device=None, dtype=None)
  • num_embeddings:嵌入字典的大小;即一个字典中有多少个词
  • embedding_dim:每个嵌入词的大小
  • padding_idx:如果指定了,padding_idx上的条目不会对渐变做出贡献;因此,在padding_idx处的嵌入向量在训练过程中没有更新,即保持为一个固定的“pad”。对于一个新构造的Embedding,在padding_idx的嵌入向量将默认为全部为零,但是可以更新为另一个值来用作填充向量。
  • max_norm:如果给定,每个范数大于max_norm的嵌入向量被重新规范化为具有范数max_norm
  • norm_type:默认为2.0;为max_norm选项计算的p-norm的p
  • scale_grad_by_freq:默认False 如果给定,这将按小批量中单词频率的倒数来缩放梯度
  • sparse:默认False ,如果为真,梯度w。r。t。权矩阵将是一个稀疏张量。有关稀疏梯度的更多细节,请参见注释。
  • embedding_weight:可学习权值模块,形状为:(num_embeddings,embedding_dim),其值采样来自于 N ? ( 0 , 1 ) N\sim(0,1) N?(0,1)

1.2 代码-随机生成表

  • 代码:
# -*- coding: utf-8 -*-
# @Project: zc
# @Author: zc
# @File name: embedding_test
# @Create time: 2022/2/9 22:13import torch
from torch import nnembeddings = nn.Embedding(10, 3,padding_idx=2)
input = torch.LongTensor([[1, 2, 4, 5], [4, 3, 2, 9]])
# padding_idx=2;表示将第2行填充为0;
# input的意思是我们从创建的表格中拿去指定的行出来
# [1,2,4,5] 代表拿出来 第1行,第2行,第4行,第5行
# [4,3,2,9] 代表拿出来 第4行,第3行,第2行,第9行
output = embeddings(input)print(f"embeddings.weight={
      embeddings.weight}")
print(f"input={
      input}")
print(f"output={
      output}")
  • 结果:
embeddings.weight=Parameter containing:
tensor([[ 0.6994, -0.1277, -0.5135],[ 0.4721, -0.7914,  0.2188],[ 0.0000,  0.0000,  0.0000],[ 0.5628,  0.6102, -0.0117],[-1.0229, -1.4277, -1.2109],[-0.6633,  0.1509, -0.8726],[ 0.2847, -0.0359, -0.4973],[ 0.5888,  0.9830,  0.9432],[ 0.1455,  0.3187,  0.9861],[-1.4602,  1.1570,  0.1492]], requires_grad=True)
input=tensor([[1, 2, 4, 5],[4, 3, 2, 9]])
output=tensor([[[ 0.4721, -0.7914,  0.2188],[ 0.0000,  0.0000,  0.0000],[-1.0229, -1.4277, -1.2109],[-0.6633,  0.1509, -0.8726]],[[-1.0229, -1.4277, -1.2109],[ 0.5628,  0.6102, -0.0117],[ 0.0000,  0.0000,  0.0000],[-1.4602,  1.1570,  0.1492]]], grad_fn=<EmbeddingBackward>)

1.3 代码-自定义表

# -*- coding: utf-8 -*-
# @Project: zc
# @Author: zc
# @File name: embedding_test_new
# @Create time: 2022/4/25 15:29import torch
from torch import nn# 自定义一个3行4列的矩阵
my_source = torch.arange(12, dtype=torch.float32).reshape((3, 4))
# my_source=tensor([[ 0., 1., 2., 3.], 第 0 行
# [ 4., 5., 6., 7.], 第 1 行
# [ 8., 9., 10., 11.]]) 第 2 行
# 将自定义的表格作为nn.Embedding处理
my_table = nn.Embedding.from_pretrained(my_source)# input为查询索引表
input = torch.Tensor([[1,2],[0,2]]).to(torch.int32)
# [[1,2],[0,2]]表示从3行4列表格中分别拿到如下行
# [1,2]: 第1行[4,5,6,7],第2行[8,9,10,11]
# [0,2]: 第0行[0,1,2,3],第2行[8,9,10,11]
# 根据input的索引表去索引自定义表格
output = my_table(input)
# 所以output输出如下:# output=tensor([[[ 4., 5., 6., 7.],
# [ 8., 9., 10., 11.]],
# 
# [[ 0., 1., 2., 3.],
# [ 8., 9., 10., 11.]]])# 打印自定义表格
print(f"my_source={
      my_source}")print(f"my_table={
      my_table}")
print(f"output={
      output}")

2. nn.EmbeddingBag

nn.Embedding嵌入式词袋,就是在原来的nn.Embedding的基础上加上一个mode ;注意,在这里我代码测试是选出的行组成的词表后求和用的是torch.sum(dim=0) 。很奇怪是不是官网错了,以下为我的代码测试结果
在这里插入图片描述

2.1 代码

import torch
from torch import nn# an EmbeddingBag module containing 10 tensors of size 3
# 创建一个词袋,这个词袋组成如下:
# 1. 先创建一个大小为10行3列的词矩阵
# 2. 词袋的方式为求和,即 先用输入的索引矩阵求得一个输出得到output
# 3. output_bag = torch.sum(output,dim=0)# 实例化一个EmbeddingBag
embedding_sum = nn.EmbeddingBag(10, 3, mode='sum')# 为了验证思路正确性,得到embedding_sum的权重weight
embedding_bag_weight = embedding_sum.weight# 打印权重矩阵 embedding_bag_weight
print(f"embedding_bag_weight={
      embedding_bag_weight}")
# embedding_bag_weight=Parameter containing:
# tensor([[ 1.2337, -1.1877, 1.6401], 第 0 行
# [-0.7979, -1.3023, -1.6140], 第 1 行
# [ 0.1214, -1.3181, 0.2492], 第 2 行
# [-0.2009, -1.7084, -1.6683], 第 3 行
# [-1.2780, 0.6330, -0.9713], 第 4 行
# [ 0.0917, -0.8060, 1.1740], 第 5 行
# [-0.1560, -0.9084, 2.6637], 第 6 行
# [-0.1871, 0.9832, 0.1025], 第 7 行
# [ 0.9361, 1.2824, -1.1812], 第 8 行
# [-0.7051, 0.3102, 0.4746]], 第 9 行 requires_grad=True)
# a batch of 2 samples of 4 indices each# input 表示要获取词表中的第 [1,2,4,5,4,3,2,9] 行
# 得到 output_table如下:
# [-0.7979, -1.3023, -1.6140], 第 1 行 0
# [ 0.1214, -1.3181, 0.2492], 第 2 行 1
# [-1.2780, 0.6330, -0.9713], 第 4 行 2
# [ 0.0917, -0.8060, 1.1740], 第 5 行 3
# [-1.2780, 0.6330, -0.9713], 第 4 行 4
# [-0.2009, -1.7084, -1.6683], 第 3 行 5
# [ 0.1214, -1.3181, 0.2492], 第 2 行 6
# [-0.7051, 0.3102, 0.4746]], 第 9 行 7
input = torch.tensor([1,2,4,5,4,3,2,9], dtype=torch.long)# offsets表示需要将 output_table 进行切割求和
# 第一份为 output_bag[0] = torch.sum(output_table[:4],dim=0) ;
# 第二份为 output_bag[1] = torch.sum(output_table[4:],dim=0) ;
offsets = torch.tensor([0,4], dtype=torch.long)
output_bag = embedding_sum(input, offsets)
print(f"embedding_sum(input, offsets)={
      output_bag}")# 为了验证我们的想法,我们需要创建一个词表,词表的权重为embedding_bag_weight
my_embedding1 = nn.Embedding.from_pretrained(embedding_bag_weight)# 根据同样的输入得到索引后的词表my_output1
my_output1 = my_embedding1(input)print(f"my_output1={
      my_output1}")# 将my_output1[:4] 前 4 行 按照dim=0求和,即行与行之间求和,得到sum0
sum0 = torch.sum(my_output1[:4],dim=0)
print(f"sum0={
      sum0}")# 将my_output1[4:] 后 4 行 按照dim=0求和,即行与行之间求和,得到sum1
sum1 = torch.sum(my_output1[4:],dim=0)
print(f"sum1={
      sum1}")# 将sum0,sum1按照行堆叠起来
cus_sum = torch.cat([sum0.unsqueeze(0),sum1.unsqueeze(0)],dim=0)
print(f"cus_sum={
      cus_sum}")# 为了验证思路是否正确,将通过nn.EmbeddingBag 求得的结果output_bag
# 自定义求得的结果cus_sum 进行对比,如果为true,表示思路正确
flag = torch.isclose(output_bag, cus_sum)print(f"flag={
      flag}")
# flag=tensor([[True, True, True],
# [True, True, True]])

3. 小结

  • nn.Embedding:

nn.Embedding 步骤如下:

  1. 创建一个m行n列的矩阵词表table
  2. 根据输入的索引来按行从词表table中求得相关行得到output
  • nn.EmbeddingBag:
  1. 创建一个m行n列的矩阵词表table
  2. 根据输入的索引来按行从词表table中求得相关行得到output
  3. 将output 按照 进行分类得到批次batch,如果mode=‘sum’ 表示我们按照torch.sum(batch[0],dim=0)
  相关解决方案