参考链接
正文
类定义
1 | class torch.nn.Embedding(num_embeddings, embedding_dim, |
给一个编号,嵌入层就能返回这个编号对应的嵌入向量,嵌入向量反映了各个编号代表的符号之间的语义关系。
参数
num_embeddings
(int): 嵌入字典的大小embedding_dim
(int): 每个嵌入向量的大小padding_idx
(int, 可选): 如果指定,padding_idx处的条目不会贡献梯度;因此,训练期间padding_idx处的嵌入向量不会更新。它保持为固定的“填充”。对于新构建的Embedding,padding_idx处的嵌入向量将默认为全零。max_norm
(float, 可选): 如果给定,每个嵌入向量的范数大于max_norm时,将被重新标准化为范数max_norm。norm_type
(float, 可选): 用于计算max_norm选项的p-范数的p。默认为2。scale_grad_by_freq
(bool, 可选): 如果给定,这将按照小批量中单词的频率的倒数缩放梯度。默认为False。sparse
(bool, 可选): 如果为True,权重矩阵的梯度将是一个稀疏张量。
变量
weight
(Tensor): 模块的可学习权重,形状为(num_embeddings, embedding_dim)
,从N(0,1)
初始化。
形状
- 输入:
(*)
, 包含要提取索引的任意形状的IntTensor或LongTensor - 输出:
(*, H)
, 其中 * 是输入形状,H = embedding_dim
官方解释nn.embedding是什么:
1 | A simple lookup table that stores embeddings of a fixed dictionary and size. |
什么是simple lookup table?我没有训练过这个东西,到底哪来的word embedding?底下到底是word2vec、GloVe,还是什么pretrained的东西?
答案其实很简单:都不是。实际上就是“随机”。我们再看一次这个文档,实际上,num_embeddings,第一个参数的意思就是,随便给定一个vocabulary size,比方说3,那么nn.Embedding
就会帮你准备3个空位。第二个参数embedding_dim会直接帮你决定他帮你准备的随机的representation要有几个dimensions,你比如说5。
那么你可以想成实际上就是这样:
1 | { |
为什么是5个数字呢?因为你embedding_dim设成5,如果你设成384就会有384个随机数字对应到每一个id。
但是我想处理文字,又不是数字 - Tokenizer在干嘛?你可能接下来会感到困惑的点是…可是我想处理文字,又不是数字…所以…其实tokenizer就是在做这件事。假设你想要把"你好吗"这句话拿去配合什么东西训练,那么你就可能会有个tokenizer做这件事:{你: 0, 好:1, 吗:2}。你的文字input经过tokenizer之后就会变成一串数字,比方说"你好好吗吗"就会变成[0, 1, 1, 2, 2],"你吗吗好"就会变成[0,2,2,1]。
然后经过nn.Embedding
的时候他就把刚刚的随机数字塞进去。
所以"你好好吗吗"会被转成这样(就只是去查[0, 1, 1, 2, 2]):
1 | { |
"你吗吗好"就会变成(就只是去查[0,2,2,1])(我们这边先不管padding):
1 | { |
更新参数:接下来你会有一个task可能是要训练model来分类什么东西,比方说听起来像不像脏话。那么,
1 | [[.123123, .123123, .123123, .12312, .123123], |
可能会对应到类别0(不像),
1 | [ |
可能会对应到类比1(有点像)等等。
Vocabulary Size的影响:你的第一个参数(num_embeddings)会影响到你有几个place holders可以用。刚刚我们设3,所以只有三个不同的tokens可以用。所以一旦传进去的index超过2(0,1,2三个参数),就会出错(list out of range)。所以大部分的语言模型都会设一个很大的数字,像是80000,再搭配tokenizer。
示例
1 | # 包含10个尺寸为3的张量的Embedding模块 |
1 | # 带padding_idx的示例 |