二元操作中的broadcast操作

Posted deepllz

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了二元操作中的broadcast操作相关的知识,希望对你有一定的参考价值。

  1.tensorflow有一种kernels名为BinaryOp(二元操作),像加法、减法、哈达玛积这种都属于二元操作(都是简单的数学操作),所有的二元操作逻辑都是相同的,唯独中间的运算符不同,在实现上将这个操作符作为模板参数传入,本质也是调用的Eigen的API(但是像矩阵乘这样的感觉也是二元操作,但是实现上却不同与二元操作,主要是调用了不同的Eigen API). 

  二元操作要求两个参数有相同的维度,比如矩阵相加、相减. 但是深度学习中有一种典型的应用:梯度更新的时候,以SGD为例,w-grad_w*lr,其中w一般都是多维的,而lr都是常数,相当于一个常数乘以一个多维张量. 这个操作也属于二元操作,看似很简单,但是却需要二元操作有足够的支持,这种维数不匹配的解决方法称为broadcast,简单理解就是维数扩展.

  tensorflow在实现broadcast的时候,借鉴了numpy的broadcast方法,也不是借鉴,就是直接拿过来用了. 其broadcast的实现文件在core/util/bcast.h中. 

  broadcast的原理很简单,就是维数不匹配的时候,将两个张量的其中之一或者两个都进行维数的扩展,举个例子:

a = [2 3 4] 
b = 2
c = a*b等价于c = [2 3 4]*[2 2 2] 

  也就是说看似a是和2相乘,实际上是和[2 2 2]相乘的,也就是说要事先对b进行维数扩展,扩展成和a相同维数才能进行哈达玛积的操作 .

  注:在具体实现扩展的时候,绝不是将2变为[2 2 2],这样浪费内存效率差,实际在内存中还是只有一份2存在,只不过我像上面那样讲可以方便理解. 像tensorflow在实现broadcast的时候调用了Eigen的broadcast方法,其内部实现用到了线程池或者cuda实现并发.

a = [[0 1 2]]
b = a‘
c = a*a‘
          0 1 2   0 0 0   0 0 0
等价于 c = 0 1 2 * 1 1 1 = 0 1 2
          0 1 2   2 2 2   0 2 4

  正常来说a的维数是[1,3],b的维数是[3,1],二者是不能做*操作的. 但是由于broadcast的存在,先将两个输入都变成了[3,3]维度的,二者就可以运算了.

  具体的broadcast规则可以参考https://docs.scipy.org/doc/numpy/user/basics.broadcasting.html.

  其核心主要有两点:

  ①后缀匹配:对两个输入的维数从后向前匹配,二者若兼容,就对其中一个输入的该维度进行broadcast,不兼容就表示二者不能做二元操作.

  ②什么情况算作维数兼容:维数相等或者其中一个是1.并且如果其中一个是1,那么最终的输出在该维度上的值就是另一个输入的维度.

  以下是官方的例子:

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

 不兼容的例子:

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

 

  

以上是关于二元操作中的broadcast操作的主要内容,如果未能解决你的问题,请参考以下文章

二元运算符“+”不能应用于“_”和“字符串”类型的操作数

NSError 代码检查:二元运算符“==”不能应用于两个 Int 操作数

二元运算符“==”不能应用于“字符串?”类型的操作数和 Swift 3 中的“布尔”

Python数据分析基础-1二元操作符(又全又清晰!)

出现错误:二元运算符“==”不能应用于两个“x”操作数,如何删除此对象数组中的某些元素

Android:片段内的按钮操作