113

TensorFlow 和 NumPy 的 Broadcasting 机制 聪聪的个人网站

 6 years ago
source link: https://lufficc.com/blog/tensorflow-and-numpy-broadcasting?
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

TensorFlow 和 NumPy 的 Broadcasting 机制

Oct 27, 2017

TensorFlow 采用 NumPy 的 Broadcasting 机制,来处理不同形状的 Tensor 之间的算术运算,来节省内存、提高计算效率。

NumPy 数组运算通常是逐元素(element-by-element )计算,因此要求两个数组的形状必须相同

>>> a = np.array([1.0, 2.0, 3.0])
>>> b = np.array([2.0, 2.0, 2.0])
>>> a * b
array([ 2.,  4.,  6.])

NumPy 的 Broadcasting 机制解除了这种限制,在两个数组的形状满足某种条件的情况下,不同形状的数组之间仍可以进行算术运算。最简单的就是数组乘以一个标量:

>>> a = np.array([1.0, 2.0, 3.0])
>>> b = 2.0
>>> a * b
array([ 2.,  4.,  6.])

结果和第一个 b 是数组的例子相同。可以认为标量 b 被拉伸成了和 a 相同形状的数组,拉伸后数组每个元素的值为先前标量值的复制,这样形式上和第一种例子相同,因此结果当然一样。但这只是理论上的,复制操作并不会真正进行,只是在计算时使用标量的值罢了。因此,第二个例子效率更高,因为节省了内存

Broadcasting 规则

当两个数组进行算术运算时,NumPy 从后向前,逐元素比较两个数组的形状。当逐个比较的元素值满足以下条件时,认为满足 Broadcasting 的条件:

  1. 相等
  2. 其中一个是1

当不满足时,会抛出 ValueError: frames are not aligne 异常。算术运算的结果的形状的每一元素,是两个数组形状逐元素比较时的最大值。

而且,两个数组可以有不同的维度。比如一个 ` 256x256x3 的数组储存 RGB 值,如果对每个颜色通道进行不同的放缩,我们可以乘以一个一维、形状为 (3, ) 的数组。因为是**从后向前**比较,因此 3 == 3`,符合 Broadcasting 规则 。

Image  (3d array): 256 x 256 x 3
Scale  (1d array):             3
Result (3d array): 256 x 256 x 3

当其中一个是 1 时,就会被“拉伸”成和另一个相同大小,即“复制”(没有真正复制)元素值来 Match 另一个,如:

A      (4d array):  8 x 1 x 6 x 1
B      (3d array):      7 x 1 x 5
Result (4d array):  8 x 7 x 6 x 5

更多的例子:

A      (2d array):  5 x 4
B      (1d array):      1
Result (2d array):  5 x 4

A      (2d array):  5 x 4
B      (1d array):      4
Result (2d array):  5 x 4

A      (3d array):  15 x 3 x 5
B      (3d array):  15 x 1 x 5
Result (3d array):  15 x 3 x 5

A      (3d array):  15 x 3 x 5
B      (2d array):       3 x 5
Result (3d array):  15 x 3 x 5

A      (3d array):  15 x 3 x 5
B      (2d array):       3 x 1
Result (3d array):  15 x 3 x 5

一些反例(不满足 Broadcasting 规则 ):

A      (1d array):  3
B      (1d array):  4 # trailing dimensions do not match

A      (2d array):      2 x 1
B      (3d array):  8 x 4 x 3 # second from last dimensions mismatched
>>> x = np.arange(4)
>>> xx = x.reshape(4,1)
>>> y = np.ones(5)
>>> z = np.ones((3,4))

>>> x.shape
(4,)

>>> y.shape
(5,)

>>> x + y
<type 'exceptions.ValueError'>: shape mismatch: objects cannot be broadcast to a single shape

>>> xx.shape
(4, 1)

>>> y.shape
(5,)

>>> (xx + y).shape
(4, 5)

>>> xx + y
array([[ 1.,  1.,  1.,  1.,  1.],
       [ 2.,  2.,  2.,  2.,  2.],
       [ 3.,  3.,  3.,  3.,  3.],
       [ 4.,  4.,  4.,  4.,  4.]])

>>> x.shape
(4,)

>>> z.shape
(3, 4)

>>> (x + z).shape
(3, 4)

>>> x + z
array([[ 1.,  2.,  3.,  4.],
       [ 1.,  2.,  3.,  4.],
       [ 1.,  2.,  3.,  4.]])
>>> a = np.array([0.0, 10.0, 20.0, 30.0])
>>> b = np.array([1.0, 2.0, 3.0])
>>> a[:, np.newaxis] + b
array([[  1.,   2.,   3.],
       [ 11.,  12.,  13.],
       [ 21.,  22.,  23.],
       [ 31.,  32.,  33.]])

newaxis 操作为数组 a 插入一维,变成二维 4x1 数组,因此 4x1 的数组加 (3, ) 的数组,结果为 4x3 的数组。

  1. https://docs.scipy.org/doc/numpy/user/basics.broadcasting.html

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK