学过代数的同学可能会知道,矩阵运算往往都是在两个维度相同或者相匹配(前面矩阵的列数等于后一个矩阵的行数)的矩阵之间定义的。比如加减法需要两个矩阵的维度相同,乘法需要前一个矩阵的列数与后一个矩阵的行数相等。那么在 Numpy、Pytorch 里也是同样的道理,但是在机器学习的某些算法中会出现两个维度不相同也不匹配的矩阵进行运算,那么这时候就需要广播机制来解决。
简言之,广播机制就是支持张量的框架,比如上面说到的 Numpy 和 Pytorch,应对形状不同的矩阵(高维矩阵称为张量 Tensor)进行运算所执行的操作。
在代数中,我们经常会遇到这种情况:数字与向量的乘法。其中,数字可以称为标量,向量可以看成是一维张量。运算法则很简单,就是数字依次与向量的元素相乘,乘得的向量就是结果。
Numpy 和 Pytorch 基本一致,所以用 Numpy 举例。
用代码展示就是这样:
import numpy as np
a = np.array([1, 2, 3])
b = 2
ret = a * b
# array([2, 4, 6])
在 Numpy 具体执行过程中,就会执行广播机制:首先,将标量 b 扩充成像 a 相同大小的张量,然后挨个元素做乘法。
代码如下:
import numpy as np
a = np.array([1, 2, 3])
b = np.array([2, 2, 2])
ret = a * b
# array([2, 4, 6])
查看 Numpy 文档,广播机制成功执行,需要一个条件:
In order to broadcast, the size of the trailing axes for both arrays in an operation must either be the same size or one of them must be one.
翻译为中文就是,进行运算的两个矩阵相应维度的大小要么相同,要么其中有一个为 1。举个例子来说,一个张量维度是 3x4x5,另一个张量的维度是 3x1x5,根据条件,这两个张量可以成功触发广播机制;如果另一个张量维度是 3x5x4 就不能触发广播机制。
import numpy as np
a = np.random.rand(3, 4, 5) # Generate a array of size is (3,4,5)
b = np.random.rand(3, 1, 5)
ret = a * b
# Run successfully
# ret.size = (3, 4, 5)
b = np.random.rand(3, 5, 4)
ret = a * b
# ValueError: operands could not be broadcast together with shapes (3,4,5) (3,5,4)
最终,结果矩阵的维度就是两个矩阵相应维度的最大值。
关于广播机制差不多就介绍完了,下面说一些需要注意的点。
假设,我们对有两个张量,一个维度是 4x3,另一个维度是 4,这样可以触发广播机制吗?
代码实现如下:
import numpy as np
a = np.random.rand(4, 3)
b = np.random.rand(4)
ret = a + b
# ValueError: operands could not be broadcast together with shapes (4,3) (4,)
看到这,不知道你有没有像我一样的疑惑,(4,)难道不可以看成是(4,1)吗?如果这样成立的话,根据条件是可以触发广播机制的。那么问题出在哪呢?
问题出在 b 的维度 4 是第一个维度,a 中与此相对应的是 3,这显然不满足条件。说白了就是 Numpy 中的向量默认是行向量。