我正在学习深度学习领域的注意算子。我明白,为了有效地并行计算多头注意力,输入张量(查询,键,值)必须适当地重塑。假设查询,键和值是三个形状相同的张量[N, L, D]
,其中
- N为批大小
- L为序列长度
- D为隐藏/嵌入大小,
应转化为[N*N_H, L, D_H]
张量,其中N_H为注意层的头数,D_H为每个头的嵌入大小。
q = q.contiguous().view(tgt_len, bsz * num_heads, head_dim).transpose(0, 1)
我不明白为什么他们执行view
和transpose
调用,当结果将是相同的,只是做
q = q.contiguous().view(bsz * num_heads, tgt_len, head_dim)
除了避免额外的函数调用之外,单独使用view
还可以保证生成的张量在内存中仍然是连续的,而这对于transpose
来说并不适用(据我所知)。我认为处理连续数据是有益的,只要可能,使计算更快(可能导致更少的内存访问,更好地利用数据的空间局部性,等等)。
在view
之后调用transpose
的用例是什么?
结果不一定相同:
a = torch.arange(0, 2 * 3 * 4)
b = a.view(2, 3, 4).transpose(1, 0)
#tensor([[[ 0, 1, 2, 3],
[12, 13, 14, 15]],
[[ 4, 5, 6, 7],
[16, 17, 18, 19]],
[[ 8, 9, 10, 11],
[20, 21, 22, 23]]])
c = a.view(3, 2, 4)
#tensor([[[ 0, 1, 2, 3],
[ 4, 5, 6, 7]],
[[ 8, 9, 10, 11],
[12, 13, 14, 15]],
[[16, 17, 18, 19],
[20, 21, 22, 23]]])