0%

矩阵 Broadcasting

矩阵 Broadcasting

Broadcasting就是可以让不同维度的矩阵,做算术运算的一种特殊规则。

规则就是,两个多维矩阵,如果某个维度上两个矩阵的维度不同,则把维度小的那个矩阵,在此维度上的数据"broadcasting"成维度大的那个矩阵,这样两个矩阵,就变成相同大小,就可以进行算术运算了。有个约束就是维度小的那一维必须是1,或者没有这一维,否则就会无法broadcasting。

比如

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
a = torch.randn(3,3)
b = torch.randn(1,3)
print(a)
print(b)
print(a+b)

output:

tensor([[-0.3362, 0.8403, 0.5095], # a [3*3]
[ 0.2355, 1.0402, -0.0055],
[-2.4016, 0.3533, 1.0728]])

tensor([[ 0.9663, -0.1208, 0.6794]]) # b [1*3]

tensor([[ 0.6300, 0.7195, 1.1889], # a+b [3*3]
[ 1.2018, 0.9194, 0.6739],
[-1.4353, 0.2326, 1.7522]])

这样相当于把b矩阵复制成三行,变成一个b’ [3*3] ,然后再和a进行相加

通过这样的方式可以让很多矩阵运算变简单,比如y=Wx+b ,这样b不用变成二维矩阵,他只要是个一维向量就可以依次加到不同列或者不同行上去了。

看到Broadcasting比较酷的一个应用就是在maskrcnn-benchmark代码中,求boxlist_iou时,找相交矩阵坐标点时的处理方式。

1
2
lt = torch.max(box1[:, None, :2], box2[:, :2])  # [N,M,2]
rb = torch.min(box1[:, None, 2:], box2[:, 2:]) # [N,M,2]

box1是N个box,box2是M个box,每个box都是4个数值,表示左上角坐标和右下角坐标。

现在要求box1的N个box分别和M个box之间的相交矩阵的左上角和右下角的坐标。

如果按我原来的思路就是二重循环,挨个遍历,这是简单粗暴的方式,更是最蠢的方法

1
2
3
for i<N  # 遍历N个box1
for j < M #遍历M个box2
res[i][j] = max(box1[i][:2], box2[j][:2])

而maskrcnn-benchmark的处理方式是,先把box1升一维,然后再利用broadcasting,把box1和box2维度都变成[N,M,2],然后再求对应元素的最大和最小值,就能得到需要的坐标点了。代码简单,只有一行,而且还可以利用CPU或GPU的并行计算,性能上也二重循环快两个数量级。