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的降维操作基本差不多.

      

  • 相关阅读:
    PAT 解题报告 1009. Product of Polynomials (25)
    PAT 解题报告 1007. Maximum Subsequence Sum (25)
    PAT 解题报告 1003. Emergency (25)
    PAT 解题报告 1004. Counting Leaves (30)
    【转】DataSource高级应用
    tomcat下jndi配置
    java中DriverManager跟DataSource获取getConnection有什么不同?
    理解JDBC和JNDI
    JDBC
    Dive into python 实例学python (2) —— 自省,apihelper
  • 原文地址:https://www.cnblogs.com/deepllz/p/9283772.html
Copyright © 2011-2022 走看看