首先感谢中科院计算所王子和先生提供的宝贵意见。
由于文章结构的关系,为了能够同时兼顾代码的真实和描述的通俗。我使用了一些可能会有一定误导性的举例说明。在这里做一些解释。
1. 关于 batch_size
在本系列上篇的 5.2.2. 使用向量化来提升效率,一节中。我使用了这样的描述:
举个例子:若有
batch_size
批次,每批次N
条的 Query,Key。 其计算完全可以组织成(batch_size, N, seq_len_q, depth)
点乘(batch_size, N, seq_len_q, depth)
的转置,最终得到(batch_size, N, seq_len_q, seq_len_k)
形状的张量。
熟悉深度学习的同学会发现,batch_size
这样的名字通常是用来描述一个批次的尺寸的,而并非描述批次数量。在 NLP 中,一次训练为一个批(batch),而一批若有 64 个句子,则 batch_size
为 64。在Transformer的实现中,它也是这样的含义。
举这个例子时,我是从最右维度为最小单位描述的,那么从最右数,第一维度是词嵌入(或特征向量)的维度,第二个维度是句子的维度,那第三个维度只能是批次的尺寸(而事实上,第三个维度N
是多头注意力的头数,是一个临时加入的维度,第四个维度才是批次的尺寸),描述这段文字的时候还没有介绍多头注意力,所以无奈之举将 batch_size
临时改了含义。
2. 关于多头注意力的计算图示带来的误导
这张图引用自国外的知名博客(在本系列上篇中提及)。显然为了能够更加直观易懂,这张图并非是基于 Transformer 真实的实现绘制的,而是按照多头注意力的原理绘制的。
但是一些读者看到这篇文章再结合代码可能会带来一些困惑。
在代码中,有两个关键的尺寸 depth
和 d_model
。事实上,前者和后者的唯一关系是,前者刚好是后者拆成的 8 份之一,两者之间的转换只存在于拆分多头步骤,并没有其他任何映射关系(全连接网络)。
由于这张图的抽象化:词嵌入的矩阵看起来显然小于 8 个头的 K Q V;最后多头拼接的一个长长的结果
W
O
W^O
WO转换成一个
Z
Z
Z,读者可能会认为词嵌入的深度是 depth
,再经过一次全连接网络得到一个d_model
然后拆成多头,最后输出结果拼成 d_model
再经过一次全连接得到 depth
,循环往复。
事实上并不是这样,在多个编码器解码器层中,从一开始的词嵌入的深度就是 d_model
,经过一次全连接网络得到映射后的KQV——深度同样是 d_model
,然后拆成多头,计算后拼接恰好也是d_model
。再回到一开始,循环往复。
也就是说,每一层注意力机制外,只有一层全连接网络。