zoukankan      html  css  js  c++  java
  • 二元操作中的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
    

     了解了numpy中broadcast的规则,就可以轻松看懂这部分的源码了. 其中源码部分还有一种降维的优化,优化的思路:如果两个输入的维数的比较结果和上一次是相同的,可以将这个维数和上一个维数合并到一起,再配合reshape的操作,可以实现tensor的降维. 举几个例子:

    A  (3d array): 3 × 2 × 2
    B  (3d array): 3 × 1 × 1
    可将 A reshape成 3 × 4 ,B reshape成3 × 1 再broadcast 成 3 × 4
    

      连续两次比较发现都需要将B的维度broadcast成A的,那么这两个维度就可以合并,从而达到降维的目的. 这个降维的优化和reduction_op的降维操作基本差不多.

      

  • 相关阅读:
    Redis存储对象(序列化和反序列化)
    JAVA中关于set()和get()方法的理解以及使用
    5W1H分析法
    Spring AOP的理解(通俗易懂)。
    Notepad++ 使用步骤,熟练掌握notepad++的使用技巧,无疑会大大提升专业技能。以及快捷键操作
    Int,String,Integer,double之间的类型的相互转换
    Ajax局部刷新和全局刷新的区别
    GET和POST都是什么时候用?
    ajax为什么需要json格式响应数据?
    final fially finalize区别
  • 原文地址:https://www.cnblogs.com/deepllz/p/9283772.html
Copyright © 2011-2022 走看看