定义
PyTorch 高级索引:
从笛卡尔积到点对点映射在基础索引(Basic Indexing,如 tensor[0:5, :])中,我们定义的是子空间切片。
而高级索引(Advanced Indexing)是指使用整型张量或布尔张量作为索引。
数学描述:设目标张量为 。
当我们提供 个索引张量 时,这组索引张量必须是可广播(Broadcastable的。
设它们广播后的共同形状为 。
那么高级索引的操作本质上是定义了一个映射 :
核心逻辑:输出张量 在位置 的值,是由 个索引张量在相同位置提供的坐标共同指向的。
案例分析
edge_index = self.connect_edges(res_X, batch) # 2, E
n_nodes = res_H.shape[0]
n_edges = edge_index.shape[1]
n_channels = res_X.shape[1]
n_heads = self.n_heads
row, col = edge_index
R_ij = torch.cdist(res_X[row], res_X[col], p=2) # (E, 14, 3) , (E, 14, 3) -> (E, 14, 14)
dist_rep = self.distance_expansion(R_ij).view(
row.shape[0], res_X.shape[1], res_X.shape[1], -1
) # E, 14, 14, d_edge
Q = self.W_Q(res_H).view([n_nodes, n_channels, self.n_heads, self.d]) # (N, 14, n_heads, d)
K = self.W_K(res_H).view([n_nodes, n_channels, self.n_heads, self.d])
V = self.W_V(res_H).view([n_nodes, n_channels, self.n_heads, self.d])
attend_logits = torch.matmul(Q[row].transpose(1, 2), K[col].permute(0, 2, 3, 1)).view(
[n_edges, self.n_heads, n_channels, n_channels]
) # (E, n_heads, 14, d) @ (E, n_heads, d, 14) -> (E, n_heads, 14, 14)
attend_logits /= np.sqrt(self.d) # n_edges, n_heads, 14, 14
attend_logits = attend_logits + self.sigma_D(dist_rep).permute(0, 3, 1, 2) # distance bias
attend_mask = torch.ones(n_edges, self.n_heads, n_channels, n_channels, device=res_H.device, dtype=torch.bool)
# sparse attention, only keep top k=3
attend_logits[torch.logical_not(attend_mask)] = -1e5 # do not sellect from entries not attend
_, top_indices = torch.topk(attend_logits, self.sparse_k, dim=-1, largest=True) # (E, n_heads, 14, 3)
sparse_mask = torch.zeros_like(attend_logits, dtype=torch.bool) # (E, n_heads, 14, 14)
rows = torch.arange(n_edges).view(-1, 1, 1, 1).expand(-1, n_heads, n_channels, self.sparse_k) # (E, n_heads, 14, 3)
depth = torch.arange(n_heads).view(1, -1, 1, 1).expand(n_edges, -1, n_channels, self.sparse_k) # (E, n_heads, 14, 3)
height = torch.arange(n_channels).view(1, 1, -1, 1).expand(n_edges, n_heads, -1, self.sparse_k) # (E, n_heads, 14, 3)
sparse_mask[rows, depth, height, top_indices] = True
attend_logits = attend_logits * sparse_mask
attend_logits = attend_logits * attend_mask # (E, n_heads, 14, 14)上述代码本质为坐标映射的构造. 当执行 sparse_mask[rows, depth, height, top_indices] = True 时,实际上是在手动构建这个 维坐标映射。
-
维度对齐为了对形状为 的四维张量进行精确赋值,需要提供 4 个坐标分量:
- Row 轴 ():
- Depth 轴 ():
- Height 轴 ():
- Width 轴 ():
-
广播机制的数学实现使用的 torch.arange(…).view(…).expand(…) 本质上是在构造基矢量张量:
- rows: 形状 ,满足
- depth: 形状 ,满足
- height: 形状 ,满足
- 这样,当它们与形状为 的 top*indices 结合时,对于任意确定的索引位置 ,其指向的目标坐标就是:(e, \ h, \ c, \ \text{top_indices}*{e,h,c,k})