

Pytorch之Embedding与Linear的爱恨纠葛 - 奥辰
source link: https://www.cnblogs.com/chenhuabin/p/17117992.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

import torch
from torch.nn import Embedding
from torch.nn import Linear
import numpy as np
torch.manual_seed(1)
<torch._C.Generator at 0x7f89641806d0>
最近遇到的网络模型许多都已Embedding层作为第一层,但回想前几年的网络,多以Linear层作为第一层。两者有什么区别呢?
Embedding层的作用是将有限集合中的元素,转变成指定size的向量。这个有限集合可以使NLP中的词汇表,可以使分类任务中的label,当然无论是什么,最终都要以元素索引传递给Embedding。例如,将包含3个元素的词汇表W={'优', '良', '差'}中的每个元素转换为5维向量。如下所示:
# 先定义一个Embedding层:
emb = Embedding(num_embeddings=3, embedding_dim=5)
# 转换第一个元素
emb(torch.tensor([0],dtype=torch.int64))
tensor([[ 0.6589, 0.4041, 1.1573, -2.3446, -0.1704]], grad_fn=<EmbeddingBackward0>)
# 转换第二个元素
emb(torch.tensor([1],dtype=torch.int64))
tensor([[ 0.6609, -0.1838, -1.8531, 2.6256, -0.9550]], grad_fn=<EmbeddingBackward0>)
# 转换第三个元素
emb(torch.tensor([2],dtype=torch.int64))
tensor([[-0.3594, 0.0348, -1.0858, -0.6675, 1.9936]], grad_fn=<EmbeddingBackward0>)
如果超出词库规模,就会产生异常错误:
# 转换第四个元素
emb(torch.tensor([3],dtype=torch.int64))
--------------------------------------------------------------------------- IndexError Traceback (most recent call last) Cell In [29], line 2 1 # 转换第四个元素 ----> 2 emb(torch.tensor([3],dtype=torch.int64)) File ~/apps/anaconda3/envs/pytorch_1_13_0/lib/python3.10/site-packages/torch/nn/modules/module.py:1190, in Module._call_impl(self, *input, **kwargs) 1186 # If we don't have any hooks, we want to skip the rest of the logic in 1187 # this function, and just call forward. 1188 if not (self._backward_hooks or self._forward_hooks or self._forward_pre_hooks or _global_backward_hooks 1189 or _global_forward_hooks or _global_forward_pre_hooks): -> 1190 return forward_call(*input,**kwargs) 1191 # Do not call functions when jit is used 1192 full_backward_hooks, non_full_backward_hooks = [], [] File ~/apps/anaconda3/envs/pytorch_1_13_0/lib/python3.10/site-packages/torch/nn/modules/sparse.py:160, in Embedding.forward(self, input) 159 def forward(self, input: Tensor) -> Tensor: --> 160 return F.embedding( 161 input,self.weight,self.padding_idx,self.max_norm, 162 self.norm_type,self.scale_grad_by_freq,self.sparse) File ~/apps/anaconda3/envs/pytorch_1_13_0/lib/python3.10/site-packages/torch/nn/functional.py:2210, in embedding(input, weight, padding_idx, max_norm, norm_type, scale_grad_by_freq, sparse) 2204 # Note [embedding_renorm set_grad_enabled] 2205 # XXX: equivalent to 2206 # with torch.no_grad(): 2207 # torch.embedding_renorm_ 2208 # remove once script supports set_grad_enabled 2209 _no_grad_embedding_renorm_(weight, input, max_norm, norm_type) -> 2210 return torch.embedding(weight,input,padding_idx,scale_grad_by_freq,sparse) IndexError: index out of range in self
初始时,所有向量表示都是随机的,但却并非一成不变的,例如在NLP任务中,随着网络的训练,表示'优'与'良'的两个向量相似度会逐渐减小,而表示'优'与'差'的两个向量相似度会逐渐增大。
1.2 Embedding的用法¶
接下来我们详细说说pytorch中Embedding层的使用方法。Embedding类主要参数如下:
-
num_embeddings (int) - 嵌入字典的大小,即共有多少个元素需要转换
-
embedding_dim (int) - 每个嵌入向量的大小,即转换后获得向量的size
-
padding_idx (int, optional) - 如果提供的话,输出遇到此下标时用零填充
-
max_norm (float, optional) - 如果提供的话,会重新归一化词嵌入,使它们的范数小于提供的值
-
norm_type (float, optional) - 对于max_norm选项计算p范数时的p
-
scale_grad_by_freq (boolean, optional) - 如果提供的话,会根据字典中单词频率缩放梯度
-
weight weight (Tensor) -形状为(num_embeddings, embedding_dim)的模块中可学习的权值
Embedding是怎么实现的呢?其实,在初始化Embedding层时,Embedding会根据默认随机初始化num_embeddings * embedding_dim的正态分布的权重。以上面例子为例,我们看看它的参数:
emb.weight
Parameter containing: tensor([[ 0.6589, 0.4041, 1.1573, -2.3446, -0.1704], [ 0.6609, -0.1838, -1.8531, 2.6256, -0.9550], [-0.3594, 0.0348, -1.0858, -0.6675, 1.9936]], requires_grad=True)
仔细观察这些权重值,每一行都与上方{'优', '良', '差'}对应。当我们在emb中输入张量torch.tensor([0])时,输出了第一行,当我们在emb中输入张量torch.tensor([1])时,输出了第二行。所以,我们可以猜测,Embedding的工作原理就是初始化一个指定shape的矩阵,在进行转换是,根据输入的tensor值,索引矩阵的行。确实如此,Embedding源码就是这么做的。
当然,Embedding的权重参数也不一定非得随机初始化,也可以手动指定。如下所示,我们先手动初始化一个3 * 5的矩阵,然后将其作为Embedding的权重参数:
# 随机初始化一个3 * 5 的矩阵
emb_weight = torch.rand(3, 5, requires_grad=True)
这里需要注意,手动初始化参数时,最好设置requires_grad=True,后续训练时才能更新权重。
emb_weight
tensor([[0.4766, 0.1663, 0.8045, 0.6552, 0.1768], [0.8248, 0.8036, 0.9434, 0.2197, 0.4177], [0.4903, 0.5730, 0.1205, 0.1452, 0.7720]], requires_grad=True)
# 通过这个预先定义的矩阵,初始化Embedding层
emb2 = Embedding.from_pretrained(emb_weight)
# 转换第一个元素
emb2(torch.tensor([0],dtype=torch.int64))
tensor([[0.7576, 0.2793, 0.4031, 0.7347, 0.0293]])
# 查看所有权重参数
emb2.weight
Parameter containing: tensor([[0.7576, 0.2793, 0.4031, 0.7347, 0.0293], [0.7999, 0.3971, 0.7544, 0.5695, 0.4388], [0.6387, 0.5247, 0.6826, 0.3051, 0.4635]])
这种手动指定参数参数话Embedding层的方式在迁移学习中非常实用,例如在NLP任务中,我们可以使用开源的词向量模型进行初始化,使得我们的模型更快收敛。
# 初始化一个Linear层
lin = Linear(in_features=3, out_features=5)
# 随机初始化一个size为3的向量
x = torch.rand(3)
x
tensor([0.7140, 0.2676, 0.9906])
x.shape
torch.Size([3])
# 经Linear层进行转换
y = lin(x)
y
tensor([ 0.1443, 0.7431, -0.1405, -0.3098, -0.1214], grad_fn=<AddBackward0>)
y.shape
torch.Size([5])
2.2 Linear的用法¶
Linear类就3个参数:
- in_features:指的是输入张量的size
- out_features:指的是输出张量的size
- bias:是否使用偏置,默认为True,表示使用
参数也简单,不多说。我们来介绍Linear的工作原理。Linear的本质就是矩阵相乘,公式如下:
w = lin.weight
w
Parameter containing: tensor([[-0.0520, 0.0837, -0.0023], [ 0.5047, 0.1797, -0.2150], [-0.3487, -0.0968, -0.2490], [-0.1850, 0.0276, 0.3442], [ 0.3138, -0.5644, 0.3579]], requires_grad=True)
b = lin.bias
b
Parameter containing: tensor([ 0.1613, 0.5476, 0.3811, -0.5260, -0.5489], requires_grad=True)
我们尝试进行手动运算:
x.matmul(w.T) + b
tensor([ 0.1443, 0.7431, -0.1405, -0.3098, -0.1214], grad_fn=<AddBackward0>)
看,结果与上方直接使用Linear层进行转换也是一样的。
Linear层的参数也可以进行手动修改:
lin_weight = torch.rand(3, 5, requires_grad=True)
lin_weight
tensor([[0.0555, 0.8639, 0.4259, 0.7812, 0.6607], [0.1251, 0.6004, 0.6201, 0.1652, 0.2628], [0.6705, 0.5896, 0.2873, 0.3486, 0.9579]], requires_grad=True)
from torch.nn import Parameter
不过必须转为Parameter才能成功:
lin.weight = Parameter(lin_weight)
3 Embedding与Linear的区别¶
-
Embedding只针对数据集规模有限的离散型数据,Linear即可用于离散型数据,也可用于连续型数据,且对数据集规模无限制。对于Embedding能实现的功能,Liner都能实现,只不过需要先进性一次手动one-hot编码。
-
Embedding本质是通过元素的索引,获取矩阵对应行作为输出,而Linear本质是矩阵相乘。
</div
Recommend
-
33
大部分航空公司处于“非波音即空客”的狭窄选择渠道之间
-
53
本站内容均来自兴趣收集,如不慎侵害的您的相关权益,请留言告知,我们将尽快删除.谢谢. 自己一直以来都是使用的pytorch,最近打算好好的看下tensorflow,新开一个系列:pytorch和tensorflow的爱恨情仇(相爱相杀。。。) ...
-
39
pytorch和tensorflow的爱恨情仇之基本数据类型 pytorch和tensorflow的爱恨情仇之张量
-
14
本站内容均来自兴趣收集,如不慎侵害的您的相关权益,请留言告知,我们将尽快删除.谢谢. pytorch版本:1.6.0 tensorflow版本:1.15.0 关于参数初始化,主要的就是一些数学中的分布,比如正态分布、均匀分布等等。...
-
9
HarmonyOS - 本地相册的纠葛-51CTO.COM HarmonyOS - 本地相册的纠葛 作者:庄茂裕 2022-03-02 15:59:37 前几天有个同事问我如何把图片存在系统相册的图片,当时我就懵逼了,鸿蒙的好像真的不怎么...
-
7
真功夫和“李小龙”再起纠葛,曾经的中式连锁第一品牌怎么了?雷达财经·2022-08-27 03:30真功夫不仅要面对同行们的竞争压力,还惹上商标侵权官司,难言轻松...
-
7
Pytorch学习笔记之tensorboard ...
-
6
Pytorch优化过程展示:tensorboard ...
-
14
Pytorch建模过程中的DataLoader与Dataset
-
4
一罐红牛养出3位富豪,7年纠葛未了 这场长久的商标大战,没有人是赢家。 华彬集团与泰国天丝的红牛商标之争依然未能结束。在近日,泰国天丝表示收到了一份最新的判决书,中国红牛相关企业被禁止生产销售“红牛维生素功能饮料”。并同时...
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK