深度学习embedding方法,降维,以及pytorch中使用embedding

这篇文章主要是学习笔记,参考了多篇文章,参考文献见最后

1 .什么是Embedding

Embedding,中文直译为“嵌入”,常被翻译为“向量化”或者“向量映射”。在整个深度学习框架中都是十分重要的“基本操作”,不论是NLP(Natural Language Processing,自然语言处理)、搜索排序,还是推荐系统,或是CTR(Click-Through-Rate)模型,Embedding都扮演着重要的角色。

1.1 什么是Embedding

形式上讲,Embedding就是用一个低维稠密的向量“表示”一个对象,这里所说的对象可以是一个词(Word2vec),也可以是一个物品(Item2vec),亦或是网络关系中的节点(Graph Embedding)。其中“表示”这个词意味着Embedding向量能够表达相应对象的某些特征,同时向量之间的距离反映了对象之间的相似性。

那么究竟什么是Embedding呢?对他进行直译是嵌入式、嵌入层

很开心地告诉你,它能把万物嵌入万物,是沟通两个世界的桥梁,是打破次元壁的虫洞!

用数学的话来说:“它是单射且同构的(看到这么好的性质是不是很激动!)”

简单来说,我们常见的地图就是对于现实地理的Embedding,现实的地理地形的信息其实远远超过二维,但是地图通过颜色和等高线等来最大化表现现实的地理信息

通过它,我们在现实世界里的文字、图片、语言、视频就能转化为计算机能识别、能使用的语言,且转化的过程中信息不丢失。

假设:我们有一个2 x 6的矩阵,然后乘上一个6 x 3的矩阵后,变成了一个2 x 3的矩阵。

先不管它什么意思,这个过程,我们把一个A中的12个元素的矩阵变成C中6个元素的矩阵,直观上,大小是不是缩小了一半?

对!!!Embedding层,在某种程度上,就是用来降维的,降维的原理就是矩阵乘法

这就是嵌入层的一个作用——降维

接着,既然可以降维,当然也可以升维。

为什么要升维?

距离的远近会影响我们的观察效果

同理也是一样的,低维的数据可能包含的特征是非常笼统的,Embedding的又一个作用体现了:对低维的数据进行升维时,可能把一些其他特征给放大了,或者把笼统的特征给分开了

同时,这个Embedding是一直在学习在优化的,就使得整个拉近拉远的过程慢慢形成一个良好的观察点。

因此它就是作为这个桥梁的存在,让我们手头的东西可伸可缩,变成我们希望的样子。

1.2 Embedding技术对于深度学习推荐系统的重要性

在深度学习推荐系统中,为什么说Embedding技术对于深度学习如此重要,甚至可以说是深度学习的“基本核心操作”呢?原因主要有以下四个:

(1)在深度学习网络中作为Embedding层,完成从高维稀疏特征向量到低维稠密特征向量的转换(比如Wide&Deep、DIN等模型)。推荐场景中大量使用One-hot编码对类别、id型特征进行编码,导致样本特征向量极度稀疏,而深度学习的结构特点使其不利于稀疏特征向量的处理,因此几乎所有的深度学习推荐模型都会由Embedding层负责将高维稀疏特征向量转换成稠密低维特征向量。因此,掌握各类Embedding技术是构建深度学习推荐模型的基础性操作。

(2)作为预训练的Embedding特征向量,与其他特征向量连接后,一同输入深度学习网络进行训练(比如FNN模型)。Embedding本身就是极其重要的特征向量。相比MF等传统方法产生的特征向量,Embedding的表达能力更强,特别是Graph Embedding技术被提出后,Embedding几乎可以引入任何信息进行编码,使其本身就包含大量有价值的信息。在此基础上,Embedding向量往往会与其他推荐系统特征连接后一同输入后续深度学习网络进行训练。

(3)通过计算用户和物品的Embedding相似度,Embedding可以直接作为推荐系统的召回层或者召回策略之一(比如Youtube推荐模型等)。Embedding对物品、用户相似度的计算是常用的推荐系统召回层技术。在局部敏感哈希(Locality-Sensitive Hashing)等快速最近邻搜索技术应用于推荐系统后,Embedding更适用于对海量备选物品进行快速“筛选”,过滤出几百到几千量级的物品交由深度学习网络进行“精排”。

(4)通过计算用户和物品的Embedding,将其作为实时特征输入到推荐或者搜索模型中(比如Airbnb的embedding应用)。

2.为什么使用嵌入层Embedding?

经常提到的Embedding层有什么用? | 机器之心 (jiqizhixin.com)

那么我们为什么要使用嵌入层 Embedding呢? 主要有这两大原因:

1、使用One-hot 方法编码的向量会很高维也很稀疏。假设我们在做自然语言处理(NLP)中遇到了一个包含2000个词的字典,当使用One-hot编码时,每一个词会被一个包含2000个整数的向量来表示,其中1999个数字是0,如果字典再大一点,这种方法的计算效率会大打折扣。

2、训练神经网络的过程中,每个嵌入的向量都会得到更新。通过上面的图片我们就会发现在多维空间中词与词之间有多少相似性,这使我们能可视化的了解词语之间的关系,不仅仅是词语,任何能通过嵌入层 Embedding 转换成向量的内容都可以这样做。

上面说的概念可能还有些不清楚,那我们就举个例子看看嵌入层 Embedding 对下面的句子怎么处理的。Embedding的概念来自于word embeddings,如果您有兴趣阅读更多内容,可以查询 word2vec 。

3.案例

3.1我们再来聊聊语义理解中Word Embedding

理解了它是沟通两个世界的桥梁后,我们再看个例子,它是如何运用在文本数据中的?

如下图所示,我们可以通过将两个无法比较的文字映射成向量,接下来就能实现对他们的计算。

例如:

queen(皇后)= king(国王)- man(男人)+ woman(女人)

这样计算机能明白,“皇后啊,就是女性的国王呗!”

walked(过去式)= walking(进行时)- swimming(进行时)+ swam(过去式)

同理计算机也能明白,“walked,就是walking的过去式啦!”另外,向量间的距离也可能会建立联系,比方说“北京”是“中国”的首都,“巴黎”是“法国”的首都,那么向量:|中国|-|北京|=|法国|-|巴黎|

强调:

Embedding 的基本内容大概就是这么多啦,然而我想说的是它的价值并不仅仅在于 word embedding 或者 entity embedding 再或者是多模态问答中涉及的 image embedding,而是这种能将某类数据随心所欲的操控且可自学习的思想

通过这种方式,我们可以将神经网络深度学习用于更广泛的领域,Embedding 可以表示更多的东西,而这其中的关键在于要想清楚我们需要解决的问题和应用 Embedding 表示我们期望的内容。

3.2 聊聊编码中的entity embedding

什么是实体嵌入(Entity Embeddings)

在处理机器学习问题时,有一个问题必须思考:如何编码数据集中的类别变量?

类别编码的两个基本方法是独热编码(onehot encoding)和标签编码(label encoding)

独热编码:直观来说就是有多少个状态就有多少比特,而且只有一个比特为1,其他全为0的一种码制。

标签编码:将类别变量表示为连续的数值型变量。

举个例子:

假如有三种颜色特征:红、黄、蓝。 我们需要对其进行向量化或者数字化编码。

那么令:红=1,黄=2,蓝=3,就实现了标签编码,即给不同类别以标签。然而这意味着机器可能会学习到“红<黄<蓝”,但这并不是我们的本意,我们只希望机器能区分它们,并无大小的区别。

这时就要引入独热编码。因为有三种颜色状态,所以就有3个比特。即红色: [ 1 , 0 , 0 ] [1, 0, 0] [1,0,0],黄色: [ 0 , 1 , 0 ] [0, 1, 0] [0,1,0],蓝色: [ 0 , 0 , 1 ] [0, 0, 1] [0,0,1] 。如此一来每两个向量之间的距离都是 2 \sqrt{2} 2​,在向量空间距离都相等,所以这样不会出现偏序性,基本不会影响基于向量空间度量算法的效果。

但是独热编码变量会导致非常稀疏的向量,这在计算上是无效的,并且难以优化。

实体嵌入则很好的解决了独热编码和标签编码存在的问题。

实体嵌入

实体嵌入基本上将标签编码方法上升了一个层次,它不仅仅是将一个整数分配给一个类别,而是整个向量这个向量可以是任意尺寸,通过一个神经网络来学习这个表达。

嵌入提供了有关不同类别之间距离的信息。使用嵌入的优点在于,在神经网络的训练期间,也要训练分配给每个类别的向量。因此,在训练过程结束时,我们最终会得到一个代表每个类别的向量。这些训练过的嵌入被可视化,为每个类别提供可视化

deep learning is very deep

使用嵌入层embedding 的第一步是通过索引对该句子进行编码,这里我们给每一个不同的单词分配一个索引,上面的句子就会变成这样:

1、2、3、4、1

接下来会创建嵌入矩阵,我们要决定每一个索引需要分配多少个“潜在因子”,这大体上意味着我们想要多长的向量,通常使用的情况是长度分配为32和50。在这篇文章中,为了保持文章可读性这里为每个索引指定6个潜在因子。嵌入矩阵就会变成这样:

嵌入矩阵

这样,我们就可以使用嵌入矩阵而不是庞大的one-hot编码向量来保持每个向量更小。简而言之,嵌入层embedding在这里做的就是把单词“deep”用向量[.32, .02, .48, .21, .56, .15]来表达。然而并不是每一个单词都会被一个向量来代替,而是被替换为用于查找嵌入矩阵中向量的索引。其次这种方法面对大数据时也能有效计算。由于在深度神经网络的训练过程中嵌入向量也会被更新,我们就可以探索在高维空间中哪些词语之间具有相似性,再通过使用t-SNE 这样的降维技术就可以将这些相似性可视化

4、深入理解embedding的本质

首先,继续假设我们有一句话,叫“公主很漂亮”,如果我们使用one-hot编码,可能得到的编码如下:

公 [0 0 0 0 1]
主 [0 0 0 1 0]
很 [0 0 1 0 0]
漂 [0 1 0 0 0] 
亮 [1 0 0 0 0]
咋一眼看过似乎没毛病,其实本来人家也没毛病,或者假设咱们的词袋更大一些

公 [0 0 0 0 1 0 0 0 0 0]
主 [0 0 0 1 0 0 0 0 0 0]
很 [0 0 1 0 0 0 0 0 0 0]
漂 [0 1 0 0 0 0 0 0 0 0] 
亮 [1 0 0 0 0 0 0 0 0 0]
假设吧,就假设咱们的词袋一共就10个字,则这一句话的编码如上所示。

这样的编码,最大的好处就是,不管你是什么字,我们都能在一个一维的数组里用01给你表示出来。并且不同的字绝对不一样,以致于一点重复都没有,表达本征的能力极强。

但是,因为其完全独立,其劣势就出来了。表达关联特征的能力几乎为0!!!

我给你举个例子,我们又有一句话“王妃很漂亮”

那么在这基础上,我们可以把这句话表示为

王 [0 0 0 0 0 0 0 0 0 1]
妃 [0 0 0 0 0 0 0 0 1 0]
很 [0 0 1 0 0 0 0 0 0 0]
漂 [0 1 0 0 0 0 0 0 0 0] 
亮 [1 0 0 0 0 0 0 0 0 0]
从中文表示来看,我们一下就跟感觉到,王妃跟公主其实是有很大关系的,比如:公主是皇帝的女儿,王妃是皇帝的妃子,可以从“皇帝”这个词进行关联上;公主住在宫里,王妃住在宫里,可以从“宫里”这个词关联上;公主是女的,王妃也是女的,可以从“女”这个字关联上。

但是呢,我们用了one-hot编码,公主和王妃就变成了这样:

公 [0 0 0 0 1 0 0 0 0 0]
主 [0 0 0 1 0 0 0 0 0 0]
王 [0 0 0 0 0 0 0 0 0 1]
妃 [0 0 0 0 0 0 0 0 1 0]
你说,你要是不看前面的中文注解,你知道这四行向量有什么内部关系吗?看不出来,那怎么办?

既然,通过刚才的假设关联,我们关联出了“皇帝”、“宫里”和“女”三个词,那我们尝试这么去定义公主和王妃

公主一定是皇帝的女儿,我们假设她跟皇帝的关系相似度为1.0;公主从一出生就住在宫里,直到20岁才嫁到府上,活了80岁,我们假设她跟宫里的关系相似度为0.25;公主一定是女的,跟女的关系相似度为1.0;

王妃是皇帝的妃子,没有亲缘关系,但是有存在着某种关系,我们就假设她跟皇帝的关系相似度为0.6吧;妃子从20岁就住在宫里,活了80岁,我们假设她跟宫里的关系相似度为0.75;王妃一定是女的,跟女的关系相似度为1.0;

于是公主王妃四个字我们可以这么表示:

       皇    宫  
       帝    里    女
公主 [ 1.0  0.25  1.0]
王妃 [ 0.6  0.75  1.0]
这样我们就把公主和王妃两个词,跟皇帝、宫里、女这几个字(特征)关联起来了,我们可以认为:

公主=1.0 *皇帝 +0.25*宫里 +1.0*女

王妃=0.6 *皇帝 +0.75*宫里 +1.0*女

或者这样,我们假设没歌词的每个字都是对等(注意:只是假设,为了方便解释):

       皇     宫  
       帝     里     女
公   [ 0.5  0.125   0.5]
主   [ 0.5  0.125   0.5]
王   [ 0.3  0.375   0.5]
妃   [ 0.3  0.375   0.5]
这样,我们就把一些词甚至一个字,用三个特征给表征出来了。然后,我们把皇帝叫做特征(1),宫里叫做特征(2),女叫做特征(3),于是乎,我们就得出了公主和王妃的隐含特征关系:

王妃=公主的特征(1) * 0.6 +公主的特征(2) * 3 +公主的特征(3) * 1

于是乎,我们把文字的one-hot编码,从稀疏态变成了密集态,并且让相互独立向量变成了有内在联系的关系向量。

所以,embedding层做了个什么呢?它把我们的稀疏矩阵,通过一些线性变换(在CNN中用全连接层进行转换,也称为查表操作),变成了一个密集矩阵,这个密集矩阵用了N(例子中N=3)个特征来表征所有的文字,在这个密集矩阵中,表象上代表着密集矩阵跟单个字的一一对应关系,实际上还蕴含了大量的字与字之间,词与词之间甚至句子与句子之间的内在关系(如:我们得出的王妃跟公主的关系)。他们之间的关系,用的是嵌入层学习来的参数进行表征。从稀疏矩阵到密集矩阵的过程,叫做embedding,很多人也把它叫做查表,因为他们之间也是一个一一映射的关系。

更重要的是,这种关系在反向传播的过程中,是一直在更新的,因此能在多次epoch后,使得这个关系变成相对成熟,即:正确的表达整个语义以及各个语句之间的关系。这个成熟的关系,就是embedding层的所有权重参数。
————————————————

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。原文链接:https://blog.csdn.net/weixin_42078618/article/details/84553940

5、pytorch Embedding的实战和用法解析

官方定义

nn.embedding就是一个简单的查找表,存储固定字典和大小的嵌入。

该模块通常用于存储词嵌入并使用索引检索它们。模块的输入是索引列表,输出是相应的词嵌入。

个人理解:

  • nn.embedding就是一个字典映射表,比如它的大小是128,0~127每个位置都存储着一个长度为3的数组,那么我们外部输入的值可以通过index (0~127)映射到每个对应的数组上,所以不管外部的值是如何都能在该nn.embedding中找到对应的数组。想想哈希表,就很好理解了。
  • 既然是映射表,那么外部的输入的值肯定不能超过最大长度,比如128,同时下限也是。官方的文档如下,torch.nn.embedding:

官方的文档如下,torch.nn.embedding:

5.1简单说明(一维变二维)

首先我们定义一个embedding

embedding = torch.nn.Embedding(10, 3)


这里第一个参数是num_embeddings=10 表示embedding词典尺寸

第二个参数embedding_dim=3 表示embedding向量尺寸

在pytorch 源码中,对于embedding层的用处有下面一句话的定义:

A simple lookup table that stores embeddings of a fixed dictionary and size
一种简单的查找表,用于存储固定字典和大小的embedding.

注意,在这里重点是 固定的,再往下找,发现大小为(num_embeddings, embedding_dim)。总结来讲,就是embedding有一个固定大小的二维权重,用来为输入做映射。

在本文例子中是(10,3),那么这个权重就是 尺寸为(10,3)的二维向量

接着咱们定义一个输入,是一个long类型的tensor变量。

input = torch.LongTensor([1,2,3,4])
result = embedding(input)

我们查看一下输出result

result=
[[-0.0376,  0.9428,  0.2284],
[-0.6415, -0.9858, -0.3793],
[ 1.6913,  0.1721,  0.9647],
[ 0.7479, -1.1152,  1.2624]]

我们看到,他的输出是一个大小(4,3)的二维向量。

那这里有一个疑问点输入input是如何转化为这个二维矩阵的,这中间发生了什么变化?

我只是输入了一个一维向量,怎么就转化成了(4,3)大小的二维向量?

我们先来输出一下这个权重矩阵的值:

weight=
[[ 0.3213,  0.7880, -1.3707],
  [-0.0376,  0.9428,  0.2284],
  [-0.6415, -0.9858, -0.3793],
  [ 1.6913,  0.1721,  0.9647],
  [ 0.7479, -1.1152,  1.2624],
  [ 0.2783, -1.6462,  0.3029],
  [ 0.2192,  0.2041,  0.1359],
  [-0.1547,  0.3126,  0.2193],
  [ 0.2389, -1.0764, -0.3257],
  [ 0.0900,  0.7144,  0.6510]]

既然 input 通过这个[10,3]权重矩阵转化为上面那个[4,3]矩阵的,他们之间会不会有什么联系

我们将这两个值放在一块儿进行一下对比

发现,这几行的值竟然完全一样。而且是从第二行开始的。

那么,用反推的思想来看x1*weight=result,可以写出

x1=
[[0,1,0,0,0,0,0,0,0,0],
 [0,0,1,0,0,0,0,0,0,0],
 [0,0,0,1,0,0,0,0,0,0],
 [0,0,0,0,1,0,0,0,0,0]
 ]

这不就是one-hot编码嘛,只在自己所属的位置是1,其他位置都是0.

这里还能够确定一点,input变化成x1 是绝对变化。绝对变化意思就是 我只根据你input里面的值,是多少,它的ont-hot就在哪里是1,从上面结果中也能够证明。x1其实是(4,10)onehot的矩阵了

还有一点,我们设置的num_embedding=10,这意味着我们input的输入值必须小于10,如果大于等于10就会报错。

总结
embedding 管理着一个大小固定的二维向量权重,其input输入值它首先转化为one-hot编码格式,将转化为后的one-hot 与权重矩阵做矩阵乘法,就得到了每一个input的embedding输出。由于这个embedding权重是可训练的,所以在最训练后的权重值,能够表达不同字母之间的关系。
————————————————

  版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。原文链接:https://blog.csdn.net/lzx159951/article/details/118884107

5.2 pytorch embedding输入的问题

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,则与权重矩阵相关的梯度转变为稀疏张量。

一般就是前用两个参数
第2个参数 embedding_dim 就是嵌入向量的维度,即用embedding_dim值的维数来表示一个基本单位。
第1个参数 num_embeddings 就是生成num_embeddings个嵌入向量。
比如下面的代码,生成6个嵌入向量,每个嵌入向量的维度是2,
然后通过 .weight 看到生成的都是随机数:

embedding = nn.Embedding(6, 2)
print(embedding.weight)
Parameter containing:
tensor([[-0.7965, -0.2459],
        [ 1.1508, -0.7320],
        [ 0.0154, -0.2846],
        [ 0.2236, -0.0293],
        [ 0.5198, -1.1245],
        [ 0.7478,  0.3544]], requires_grad=True)
那么我们是如何使用这些向量表示我们的词呢?
是索引。
看下面的代码:
embedding = nn.Embedding(6, 2)
x=torch.rand((3,2))*10
embedding(x)

这样的结果是报错,因为x是float数据,float不能作为索引:
要求输入必须是整数型

embedding = nn.Embedding(6, 2)
print('embedding.weight:',embedding.weight)
t = torch.ones((100,100)).to(int)
print('embedding(t):',embedding(t))
embedding.weight: Parameter containing:
tensor([[ 0.2666,  1.6938],
        [-0.2191,  0.2008],
        [ 0.0308,  0.3599],
        [ 0.6266, -1.1199],
        [ 2.0277, -0.3861],
        [-0.1880,  0.6900]], requires_grad=True)
embedding(t): tensor([[[-0.2191,  0.2008],
         [-0.2191,  0.2008],
         [-0.2191,  0.2008],
         ...,
         [-0.2191,  0.2008],
         [-0.2191,  0.2008],
         [-0.2191,  0.2008]],

        [[-0.2191,  0.2008],
         [-0.2191,  0.2008],
         [-0.2191,  0.2008],

输出结果很长,所以这里只展示一部分。我们先生成了一个 t , t 相当于我们的文本了,一共有100个句子,每个句子100个词。而我们对 t 的编码结果是每个词都是[-0.2191, 0.2008],我们发现这和embedding.weight[1]是一样的(因为我们生成的t都是1)。因为Embedding就是根据索引值编码的。

Embedding生成的每个嵌入向量都通过索引存储起来,以供后期编码使用。
又比如:

embedding = nn.Embedding(6, 2)
print('embedding.weight:',embedding.weight)
x=(torch.rand((3,2))*10).to(int)
print('x:',x)
print('embedding(x):',embedding(x))
embedding.weight: Parameter containing:
tensor([[-0.8326, -0.4983],
        [ 2.1820, -0.1443],
        [-0.4806, -0.1235],
        [ 0.3978, -0.2895],
        [ 1.2748, -1.1211],
        [-0.4095, -0.5246]], requires_grad=True)
x: tensor([[2, 6],
        [4, 5],
        [4, 7]])

报错

我们可以看到报错信息索引超过了范围,因为Embedding的最大索引为5,而x中的6和7超过了这个值,所以就报错了。

并且nn.Embedding()是可以训练的,参考这个:
torch.nn.Embedding是否有梯度,是否会被训练

注:其实这个和nn.Parameter()的工作原理是一样的,都是先生成一些嵌入向量,然后调用它对自己的输入进行编码时,通过索引来取值编码。
————————————————

 版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。 原文链接:https://blog.csdn.net/qq_49030008/article/details/120257353

5.3 多个自动驾驶车状态的embedding方法

对于多辆自动驾驶车辆的特征,如果你希望使用嵌入方法来处理这些特征,可以考虑以下步骤:

  1. **确定嵌入维度:**首先,确定要将特征映射到的低维空间的维度。这将是嵌入向量的长度,通常是一个超参数,需要根据数据和任务进行调优。

  2. **建立嵌入层:**在神经网络模型中添加一个嵌入层,该层将输入的离散特征索引映射到低维连续向量。在PyTorch中,可以使用nn.Embedding层来实现这一点。例如,对于25个特征,你可以为每个特征使用一个嵌入层。

  3. **将输入数据转换为索引:**将每个特征的取值转换为其在嵌入矩阵中的索引。如果特征是连续值,则可能需要将其离散化为一组离散的取值。然后,可以将这些离散化的值作为输入传递给嵌入层。

  4. **获取嵌入向量:**通过将索引传递给嵌入层来获取对应的嵌入向量。这将返回一个形状为(batch_size, embedding_dim)的张量,其中batch_size是输入数据的批量大小,embedding_dim是嵌入维度。

  5. **将嵌入向量连接或汇总:**如果有多个嵌入向量(对应于多个特征),可以选择将它们连接起来或使用汇总操作(例如平均池化)来获得单个嵌入向量。最终的嵌入向量可以作为模型的输入,用于进一步的处理和预测。(三维变二维)

import torch
import torch.nn as nn

# 定义嵌入维度和特征数
embedding_dim =3

num_states =30
# 建立嵌入层
embedding_layer = nn.Embedding(num_states, embedding_dim)

# 假设输入数据是一个形状为(batch_size, num_vehicles, num_features)的张量
batch_size = 32
num_vehicles = 5
num_features = 10
input_data = torch.randint(num_features, (batch_size, num_vehicles, num_features))

# 将输入数据传递给嵌入层获取嵌入向量
embedded_data = embedding_layer(input_data)

# 汇总嵌入向量(这里简单地使用平均池化)
pooled_embedded_data = torch.mean(embedded_data, dim=2)

print("Embedded data shape:", embedded_data.shape)
print("Pooled embedded data shape:", pooled_embedded_data.shape)

(1)其中,input_data = torch.randint(num_features, (batch_size, num_vehicles, num_features))

这句话的意思是创建了一个形状为 (batch_size, num_vehicles, num_features) 的张量,其实这里输入多大的数据都不影响,即(num_vehicles, num_features)是多大都可以,主要是 input_data,其中包含随机生成的整数值,这些整数值的范围在 [0, num_states) 之间

因为嵌入层
embedding_layer = nn.Embedding(num_states, embedding_dim)中num_states相当于字典中每个字的序列号,nn.Embedding(num_states, embedding_dim)理解为字典中有30个字,每个字有3个组成部分。

输入数据(num_vehicles, num_features)是(5,10)的可理解为有5句话,每句话有10个字,输入到embedding层后就那么输出数据是(5,10,3),即(5,10)分别对应字典的中3个组成部分

(2)具体来说,torch.randint(num_features, (batch_size, num_vehicles, num_features)) 调用了 PyTorch 的 randint 函数,生成了指定形状的随机整数张量,范围是从 0 到 num_features-1

(3)embedded_data 大小是( batch_size, num_vehicles, num_features,embedding_dim)即(32,5,10,3)

(4) 汇总嵌入向量(这里简单地使用平均池化)这里是降维了。

池化Pooling是卷积神经网络中常见的一种操作,Pooling层是模仿人的视觉系统对数据进行降维,其本质是降维。在卷积层之后,通过池化来降低卷积层输出的特征维度,减少网络参数和计算成本的同时,降低过拟合现象。参考文章:

一文弄懂各大池化Pooling操作 - 知乎 (zhihu.com)

pooled_embedded_data = torch.mean(embedded_data, dim=2)中dim=2代表的是第3个维度求均值,也就池化了embedded_data中(32,5,10,3)的10的特征,pooled_embedded_data大小是(32,5,3),即把10的特征池化了,降了一个维度。dim=0代表的是第1个维度求均值,pooled_embedded_data大小是(5,10,3).

5.4、二维变一维

# 假设有165辆车,每辆车有25个特征
num_vehicles = 165
num_states = 100
embedding_dim = 1  # 将每个特征嵌入到1维空间中

# 建立嵌入层
embedding_layer = nn.Embedding(num_states, embedding_dim)
embedding_weight=embedding_layer.weight
print('embedding.weight:',embedding_layer.weight)
# 生成模拟的车辆特征数据,假设为一个形状为(165, 25)的张量
#input_data = torch.randn(num_vehicles, num_features)#这种创建的数据在[0,1]之间,再改成整数时(0,1)就输入到embedding_layer会报错
num_features=25
# 将特征数据转换为索引形式
input_data = torch.randint(4, (num_vehicles,num_features))#创建一个形状为 (num_vehicles, num_features) 的张量 input_data,其中每个元素都是从 0 到 num_features - 1 之间的随机整数。
# 这里简单地将特征数据四舍五入到最近的整数作为索引,实际应用中可能需要更复杂的转换方法
input_indices = torch.round(input_data).long()

# 获取嵌入向量
embedded_data = embedding_layer(input_indices)#这里得到是(165,25,1)

# 汇总嵌入向量,沿着特征维度求和,得到每辆车的表示
summed_embedded_data = torch.sum(embedded_data, dim=1)

print("Summed embedded data shape:", summed_embedded_data.shape)

input_data = torch.randint(num_features, (num_vehicles, num_features))

这句话的意思是创建一个形状为 (num_vehicles, num_features) 的张量 input_data,其中每个元素都是从 0num_features - 1 之间的随机整数。这个过程利用了 PyTorch 中的 torch.randint 函数。

其中,input_indices = torch.round(input_data).long()

这句话的意思是将张量 input_data 中的所有元素四舍五入为最接近的整数,并转换为 long 类型。在这种情况下,input_data 中的每个元素都会被四舍五入为最接近的整数,并且结果将被转换为长整型。(后面会解释输入的问题)

这里是求和降维,# 汇总嵌入向量,沿着特征维度求和,得到每辆车的表示
summed_embedded_data = torch.sum(embedded_data, dim=1)

池化的具体介绍,见另一篇文章各大池化Pooling操作,以及python实践,学习笔记-CSDN博客

参考文献

【1】pytorch Embedding的实战和用法解析_python embedding-CSDN博客

【2】经常提到的Embedding层有什么用? | 机器之心 (jiqizhixin.com)

【3】Embedding技术的本质(图解) - 知乎 (zhihu.com)

【4】深入理解 Embedding层的本质_npl embedding-CSDN博客

【5】详细介绍pytorch中的nn.Embedding()_nn.embedding可以训练么-CSDN博客

  • 22
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值