这几天花了不少时间在看 Transformer,正好不知道更新什么,就在此记录一下吧。其实我并不想对于 Transformer 这个东西进行深究,只想简单的知道这个东西做了什么事情,有什么优势,以及怎么使用。网上找文档的时候发现基本上所有文档都是在讲大概念,但是很少有涉及细节的。比如我只想知道输入输出维度是多少,怎么快速的用起来看看效果,讲这些的好像并不多。
当然,我们可以自己直接看看代码的输入输出,但是这就比较麻烦,而且对于之前没研究过这方面的我来说也不是太友好。或者我们也可以直接把代码拿来跑一下看看,但是这是因为正好 Pytorch 有一个 nn.Transformer,如果换成别的没有现成的代码的东西,想快速知道输入输出其实还是挺麻烦的。今天正好搜到一篇文章记录了一些细节,在此转载记录一下。并加上自己的一些粗俗的理解,试图把问题阐述的更清晰一些。
以下一部分内容转载自:https://zhuanlan.zhihu.com/p/166608727
文章目录
隐藏
一、Transformer 输入输出维度
二、Transformer Encoder
三、Transformer Decoder
四、Pytorch nn.Transformer
一、Transformer 输入输出维度
这张图相信大家都很熟悉了。
对于机器翻译来说,一个样本是由原始句子和翻译后的句子组成的。比如原始句子是: “我爱机器学习”,那么翻译后是 “i love machine learning”。 则该一个样本就是由“我爱机器学习”和 “i love machine learning” 组成。
这个样本的原始句子的单词长度是 length=4,即‘我’ ‘爱’ ‘机器’ ‘学习’。经过 embedding 后每个词的 embedding 向量是 512。那么“我爱机器学习”这个句子的 embedding 后的维度是 [4,512 ] (若是批量输入,则embedding后的维度是 [batch, 4, 512])。
也就是说,输入维度就是 batch_size * sequence_length * embedding_dimension
如果不经过 decoder,那么 encoder 输出维度是和输入维度一样的。如果加了 decoder,就看 decoder 的输出维度怎么定义。
二、Transformer Encoder
输入在上面已经提及,下面看一下其他部分。
1、Padding
因为每个样本的原始句子的长度是不一样的,那么怎么能统一输入到 encoder 呢。此时 padding 操作登场了,假设样本中句子的最大长度是 10,那么对于长度不足 10 的句子,需要补足到 10 个长度,shape 就变为 [10, 512],补全的位置上的 embedding 数值自然就是 0 了。
2、Padding Mask
对于输入序列一般我们都要进行 padding 补齐,也就是说设定一个统一长度 N,在较短的序列后面填充 0 到长度为 N。对于那些补零的数据来说,我们的 attention 机制不应该把注意力放在这些位置上,所以我们需要进行一些处理。具体的做法是,把这些位置的值加上一个非常大的负数(负无穷),这样经过 softmax 后,这些位置的权重就会接近 0。Transformer 的 padding mask 实际上是一个张量,每个值都是一个 Boolean,值为 false 的地方就是要进行处理的地方。
3、Positional Embedding
得到补全后的句子 embedding 向量后,直接输入 encoder 的话,那么是没有考虑到句子中的位置顺序关系的。此时需要再加一个位置向量,位置向量在模型训练中有特定的方式,可以表示每个词的位置或者不同词之间的距离;总之,核心思想是在 attention 计算时提供有效的距离信息。
由于 Positional Embedding 对我来说并不是很重要,所以更具体内容大家可以直接参考上面提到的引用文献。
4、Attention
关于 attention 操作,网上讲的很多,也很简单,就不写了。不过需要值得注意的一点是,单头 attention 的 Q/K/V 的 shape 和多头 attention 的每个头的 Qi/Ki/Vi 的大小是不一样的,假如单头 attention 的 Q/K/V 的参数矩阵 WQ/WK/WV 的 shape 分别是 [512, 512](此处假设encoder的输入和输出是一样的shape),那么多头 attention (假设8个头)的每个头的 Qi/Ki/Vi 的参数矩阵 WQi/WKi/WVi 大小是 [512,512/8].
5、FeedForward
很简单,略
6、add/Norm
经过 add/norm 后的隐藏输出的 shape 也是 [10,512]。(当然你也可以规定为[10, x],那么Q/K/V的参数矩阵shape就需要变一下)
7、encoder 总体流程
让我们从输入开始,再从头理一遍单个 encoder 这个过程:
- 输入 x
- x 做一个层归一化: x1 = norm(x)
- 进入多头 self-attention: x2 = self_attention(x1)
- 残差加成:x3 = x + x2
- 再做个层归一化:x4 = norm(x3)
- 经过前馈网络: x5 = feed_forward(x4)
- 残差加成: x6 = x3 + x5
- 输出 x6
三、Transformer Decoder
训练的时候:
1. 初始 decoder 的 time step 为 1 时(也就是第一次接收输入),其输入为一个特殊的 token,可能是目标序列开始的 token(如 <BOS>),也可能是源序列结尾的 token(如<EOS>),也可能是其它视任务而定的输入等等,不同源码中可能有微小的差异,其目标则是预测翻译后的第1个单词 (token) 是什么;
2. 然后 <BOS> 和预测出来的第 1 个单词一起,再次作为 decoder 的输入,得到第 2 个预测单词;3 后续依此类推;
因为我目前只用到 encoder,decoder 部分就简单略过了。
四、Pytorch nn.Transformer
Pytorch 提供了 nn.Transformer,nn.TransformerEncoder,nn.TransformerEncoderLayer 等一系列封装好的网络供大家调用,所以我们其实不需要自己写特别细致的代码,直接调用即可。
Pytorch Transformer 教程:
https://pytorch.org/tutorials/beginner/transformer_tutorial.html
Transformer Layers:
https://pytorch.org/docs/master/nn.html#transformer-layers
这两个教程其实写的很清楚了,我们照着学习一下应该就懂了吧。