最后更新于2020.11.19
PyTorch
理解nn.Embedding 的参数和维度变换
总结自:
最常用的前两个参数是 num_embeddings
和 embedding_dim
,含义分别是词典大小和编码后的维度。词典大小是指这段输入中有多少个不同的词,也要包括pad一个,比如有5000个不同的单词就可以传入5000,此时的编号则是0~4999。
另外,第三个参数 padding_idx
默认为0
,所以默认情况下idx=0
的那个元素将会被当作padding
。
- 这个模型定义好了以后,输入的内容如何确定?输出又是什么?懒得举例子了,仔细读完一定能懂
- 首先肯定需要一个
word2id
词典,储存单词到词典序号的映射,假设现在我希望输入n
个句子,句子的长度可能不一致。 - 此时是单词表示的,所以先要对输入进行标准化,也就是大写转小写、标点分离、分词,例如可以用
nltk
的tokenize
做。接着把这些句子按照长度从大到小排序,也需要一个list,存储每个句子的长度。 - 然后用上面的词典把这些句子的单词转换为序号,这样输入就全部变成了数字。
- 之后把每个句子后面加上一个
EOS
表示句子结束,假设我使用idx=1表示EOS。 - 因为句子长度不一致,所以要做
padding
,假设我使用idx=0
作为paddding_idx
,那么所有句子现在的长度都变成了跟原先最长的句子一样长了,原本较短的句子后面全都被补上了0
- 上面所说的
n
个句子就能够看作一个batch
一起进行训练,但是现在还不能直接作为Embedding
层的输入。现在如果把这n
个句子组织成Tensor
,那么一行是一个句子,一共n
行,假设shape
是[n, k]
。因为RNN的每一步的输入是一批单词,一共是batch_size
个,所以要做一个类似转置的操作,这样每个句子都变成了一列,变成[k, n]
,然后就能够作为Embedding
的输入了。 - 输出可见多了一个第三维,这就决定于刚才定义的
embedding_size
参数是多少了。
- 首先肯定需要一个
补充来自 关于nn.embedding的维度的定义,函数的理解,一些需要注意的点 的注意之处:
nn.embedding的输入只能是编号,不能是隐藏变量,比如one-hot,或者其它,这种情况,可以自己建一个自定义维度的线性网络层,参数训练可以单独训练或者跟随整个网络一起训练(看实验需要)
如果你指定了padding_idx,注意这个padding_idx也是在num_embeddings尺寸内的,比如符号总共有500个,指定了padding_idx,那么num_embeddings应该为501
embedding_dim的选择要注意,根据自己的符号数量,举个例子,如果你的词典尺寸是1024,那么极限压缩(用二进制表示)也需要10维,再考虑词性之间的相关性,怎么也要在15-20维左右,虽然embedding是用来降维的,但是也要注意这种极限维度,结合实际情况,合理定义
bmm()函数
首先是mm(),用于二位矩阵的乘法,bmm就是加上了batch(是不是可以理解为有一批的二维矩阵进行计算?)
(如果猜想没错,那么就比如三维*三维,需要第一个维度相同,因为是一批,后面两个维度就是真正的矩阵,和二维矩阵相乘的要求一样了)
11.11 补充:上面的说法没错,如(bnm) 与 (bmp) 就能够用bmm作乘法,结果是(bnp)
其他乘法的函数:torch.mm(), torch.matmul(), torch.mul()等等
mm 仅用于二维矩阵,matmul用于二维以上;
mul是点乘,可以用 *
代替。
这篇博客总结得更为详细
torch.mul、torch.mm、torch.bmm、torch.matmul的区别_给时光以生命-CSDN博客
squeeze和unsqueeze
-
squeeze类似于删掉一个维度,比如有一个shape为
[1, 2, 1, 4]
的tensor,对他用squeeze(0)
就会把他变成[2, 1, 4]
的shape。如果不指定参数dim,则会把所有1维度的给去掉,就会变成[2, 4]
。如果传入了参数dim,但是实际上那个维度不是1,那么会不做任何操作,这与numpy
不同,numpy会报错。注意:官方给了Note和Warning:
Note:
The returned tensor shares the storage with the input tensor, so changing the contents of one will change the contents of the other. 说的大概是共享内存。
Warning:
If the tensor has a batch dimension of size 1, then squeeze(input) will also remove the batch dimension, which can lead to unexpected errors. 说的是如果batch维度是1,则会被去掉,导致一些其他错误。
-
unsqueeze就是反操作
torch.chunk函数
这个函数有三个参数:
- input (Tensor) – the tensor to split
- chunks (int) – number of chunks to return
- dim (int) – dimension along which to split the tensor
用处是:把input在dim维度上分成chunk个片,如果这个维度的元素(tensor长度)不能整除chunk,那么最后的一个分片会被舍弃掉
torch.index_select函数
三个参数:
torch.index_select(x, 0, indices)
,indices是tensor,这里会起一个索引的作用,把x在0维度上取出indices对应位置的元素
>>> x = torch.randn(3, 4)
>>> x
tensor([[ 0.1427, 0.0231, -0.5414, -1.0009],
[-0.4664, 0.2647, -0.1228, -1.1068],
[-1.1734, -0.6571, 0.7230, -0.6004]])
>>> indices = torch.tensor([0, 2])
>>> torch.index_select(x, 0, indices)
tensor([[ 0.1427, 0.0231, -0.5414, -1.0009],
[-1.1734, -0.6571, 0.7230, -0.6004]])
>>> torch.index_select(x, 1, indices)
tensor([[ 0.1427, -0.5414],
[-0.4664, -0.1228],
[-1.1734, 0.7230]])
评论区