前言
最近在看 yolov8 的源码的时候,第一次看到花式索引的使用,在那一行代码卡了半天的时间,从疑惑,到怀疑自我,再到愤怒,一时间无法理解,怎么有这么恶心的东西:
一个多维的数组或者是张量,使用多维数组和张量作为索引
这玩意有什么出现的必要吗?本来多维矩阵的操作已经麻烦到不行了,你索引再给我整个多维矩阵,简直逆天。
网上大多数关于花式索引的文章都是浅尝辄止,看了半天都没得到啥有用的信息,于是花了半天时间,自己测试了一下,终于理解了其中的操作。
因为 np.array 与 tensor 关于花式索引的操作都是一样的,为了省事,下面是使用的 numpy。
我们跳过一维的索引,直接进入正题,二维数组作为索引:
a = np.arange(60).reshape((3, 4, 5))
b1 = np.array([[2, 0], [0, 1]])
a
和 b1
两个数组是
a: [[[ 0 1 2 3 4]
[ 5 6 7 8 9]
[10 11 12 13 14]
[15 16 17 18 19]]
[[20 21 22 23 24]
[25 26 27 28 29]
[30 31 32 33 34]
[35 36 37 38 39]]
[[40 41 42 43 44]
[45 46 47 48 49]
[50 51 52 53 54]
[55 56 57 58 59]]]
b1: [[2, 0], [0, 1]]
例一
如果我现在要求解:a[b1, :, :]
,就是将二维数组 b1
作为 a
的第一维度的索引:
- 获得的结果是啥?
- 维度是多少?
为了方便理解,我将自己摸索的推导过程逐步分解,这样大家都可以轻松看懂:
我们知道 a[n, :, :]
的维度是 [4, 5]
,根据推导的公式,不难看出来获得的结果维度是 [2, 2, 4, 5]
例二
这次我们求 a[:, b2, :]
,b2
的值如下, 看看有什么不一样的地方(其实也是一样的)。
b2 = np.array([[0, 0], [1, 2]])
例三
前面的例一和例二都是三维数组,但是都只选择其中一个维度进行花式索引,接下来我们升级一下,如果有两个维度都进行了花式索引,我们又会获得怎么样的结果捏?
这里我们继续沿用上面的数组 a
,接下来我们要求解 a[b1, :, b2]
的结果。
这会涉及到一个广播机制,就是作为索引的 b1
和 b2
都得满足广播机制得规则才行,他们会被转换成维度一致的矩阵。讲究一个门当户对,在这里就不做过多的介绍了。
代码
大家可以跑一下下面的代码,看看结果:
import numpy as np
a = np.arange(60).reshape((3, 4, 5))
b1 = [[2, 0], [0, 1]]
b2 = [[0, 0], [1, 2]]
example_1 = a[b1, :, :]
example_2 = a[:, b2, :]
example_3 = a[b1, :, b2]
print(example_1, example_1.shape)
print(example_2, example_2.shape)
print(example_3, example_3.shape)