broadcast讲的是numpy在进行数学运算的时候,当shape中的维度不同时,numpy是如何运算的。
我们知道, 在通常情况下,两个数组要进行element-by-element的计算的时候,是需要完全一致的shape的,例如
>>> from numpy import array
>>> a = array([1.0, 2.0, 3.0])
>>> b = array([2.0, 2.0, 2.0])
>>> a * b
array([ 2., 4., 6.])
这个很容易理解,对应位置的元素直接进行了相乘
shape(1, 3) * shape(1, 3) = shape(1, 3)。
但是numpy对这种限制进行了放宽,要求shape中的dim未必要完全的一致的。例如
>>> from numpy import array
>>> a = array([1.0,2.0,3.0])
>>> b = 2.0
>>> a * b
array([ 2., 4., 6.])
在这里, b只是一个标量值,而不是一个数组。但是他跟shape(1,3)的b得到了同样的结果。那么它是如何处理的呢?
我们可以这么理解:
在跟a进行数学运算的时候,numpy将标量b进行了拉伸,或者称之为扩展、复制。类似于分身一样,为了兼容a,b创建了跟a一样多的自己来跟a进行适配,伟大的b!
![883bcb47563bd2af1ccd315f2196e5c9.gif](https://img-blog.csdnimg.cn/img_convert/883bcb47563bd2af1ccd315f2196e5c9.gif)
也就是说,numpy将数组的数学运算不仅仅的局限在了一模一样的shape情况下,而是将其进行了扩展,允许某些数组将自己进行扩展、复制,来适应整个运算。
这个运算规则总结一下就是:
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。 这种情况下,是可以计算的。
如果不符合这个运算规则的话,就会抛出 ValueError('frames are not aligned') 的异常。如果符合,跑出的结果是:一致的维度,还是不变;不一致的维度的值,取不是1的那个值。
也要注意到,这个结论里面并没有提到shape数完全一致,也就是说shape即使不一致也可以进行这个运算,只要运算的时候,数组都从最低位的维度开始对应,对应的维度满足上面的要求即可。
例如:
![6ef8d1501c20fd5bad21812be80b58ad.png](https://img-blog.csdnimg.cn/img_convert/6ef8d1501c20fd5bad21812be80b58ad.png)
shape(8,1,6,1) * shape(7,1,5) = shape(8,7,6,5)。
我们可以看下下面的代码
>>> from numpy import array
>>> a = array([[ 0.0, 0.0, 0.0],
... [10.0, 10.0, 10.0],
... [20.0, 20.0, 20.0],
... [30.0, 30.0, 30.0]])
>>> b = array([1.0, 2.0, 3.0])
>>> a + b
array([[ 1., 2., 3.],
[ 11., 12., 13.],
[ 21., 22., 23.],
[ 31., 32., 33.]])
shape(3,3) * shape(1, 3) = shape(3, 3)
他们是按照下面的方法进行运算的:
![c0b023f285f6679c394b1af830e68936.png](https://img-blog.csdnimg.cn/img_convert/c0b023f285f6679c394b1af830e68936.png)
b把自己进行了复制,从而可以进行计算了。
但是如果b不满足上面的计算条件
![678f2d5426811f38c860ced158453b2a.png](https://img-blog.csdnimg.cn/img_convert/678f2d5426811f38c860ced158453b2a.png)
这种情况下, b完全不知道该怎么复制自己,因为怎么复制都match不了a,因此是无效的。
理解了上述原理之后, 可以知道, broadcast可以很方便的做外积,例如
>>> from numpy import array, newaxis
>>> a = array([0.0, 10.0, 20.0, 30.0])
>>> b = array([1.0, 2.0, 3.0])
>>> a[:,newaxis] + b
array([[ 1., 2., 3.],
[ 11., 12., 13.],
[ 21., 22., 23.],
[ 31., 32., 33.]])
可以通过下面的方法来理解:
![dfb4f1ab2338dab1581d3ebe618f3733.png](https://img-blog.csdnimg.cn/img_convert/dfb4f1ab2338dab1581d3ebe618f3733.png)
用这种方式,很容易来做一些向量的计算。在tensorflow中,也是这么做的。
ref
(broadcasting介绍)