【问题标题】:Tensorflow, How can I compute backward pass for a given forward functionTensorflow,我如何计算给定前向函数的后向传递
【发布时间】:2017-12-30 07:00:40
【问题描述】:

我想构造一个Caffe风格的L2-norm层(好吧,我实际上想在pycaffe层中使用Tensorflow,因为使用CUDACaffe中写入.cu文件是一项繁重的任务。)

前传:
- 输入(x):n 维数组
- 输出(y):具有相同输入形状的 n 维数组
- 操作:

y = x / sqrt(sum(x^2,axis=(0,1))) # channel wise L2 normalization

class L2NormLayer:
    def __init__(self):
        self.eps = 1e-12
        self.sess = tf.Session()

    def forward(self, in_x):
        self.x = tf.constant(in_x)
        self.xp2 = tf.pow(self.x, 2)
        self.sum_xp2 = tf.reduce_sum(self.xp2, axis=(0, 1))
        self.sqrt_sum_xp2 = tf.sqrt(self.sum_xp2 + self.eps)  
        self.hat = tf.div(self.x, self.sqrt_sum_xp2)

        return self.sess.run(self.hat)

    def backward(self, dl):
        # 'dl' is loss calculated at upper layer (chain rule)
        # how do I calculate this gradient automatically using Tensorflow

        # hand-craft backward version
        loss = tf.constant(dl)
        d_x1 = tf.div(loss, self.sqrt_sum_xp2)
        d_sqrt_sum_xp2 = tf.div(-tf.reduce_sum(self.x * dl, axis=(0, 1)), (self.eps + tf.pow(self.sqrt_sum_xp2, 2)))
        d_sum_xp2 = tf.div(d_sqrt_sum_xp2, (self.eps + 2 * tf.sqrt(self.sum_xp2)))
        d_xp2 = tf.ones_like(self.xp2) * d_sum_xp2
        d_x2 = 2 * self.x * d_xp2
        d_x = d_x1 + d_x2

        return self.sess.run(d_x)

如代码中所述,如何自动使用Tensorflow 计算前向传递函数的梯度?

【问题讨论】:

    标签: tensorflow neural-network deep-learning caffe gradient-descent


    【解决方案1】:

    我认为您最好的策略是使用现有的 caffe 层来实现您的目标。
    首先,使用"Reduction"层计算x的平方L2范数:

    layer {
      name: "norm_x_sq"
      type: "Reduction"
      bottom: "x"
      top: "norm_x_sq"
      reduction_param { operation: SUMSQ axis: 1 }
    }
    

    使用"Power" 层取范数的平方根并计算其倒数:

    layer {
      name: "norm_x-1"
      type: "Power"
      bottom: "norm_x_sq"
      top: "norm_x-1"
      power_param { power: -0.5 }
    }
    

    一旦你有了分母,你需要将"Tile" 回复到与x 相同的shape

    layer {
      name: "denom"
      type: "Tile"
      bottom: "norm_x-1"
      top: "denom"
      tile_param { axis:1 tiles: N } # here you'll have to manually put the target dimension N
    }
    

    最后,使用"Eltwise"层对x进行归一化:

    layer {
      name: "x_norm"
      type: "Eltwise"
      bottom: "x"
      bottom: "denom"
      top: "x_norm"
      eltwise_param { operation: PROD }
    }
    

    一些补充说明:
    1. 如果范数很小,除以范数可能在数值上不稳定。在取平方根的倒数之前,您可能需要考虑向"norm_x_sq" 添加一个小常数。您也可以使用现有图层来做到这一点。
    2.这个例子展示了如何根据axis=1维度进行归一化。根据向量在 blob 中的排列方式,您也许可以使用 "Scale" 层进行分割,而不是 tile+eltwise。
    3. 您可能还会发现this thread 很有用。

    【讨论】:

    • 嗨@Shai,感谢您的巧妙解决方案。这是我目前拥有的最有效的解决方案。我会尽快部署它。但是,我正在寻找一种更通用的方法来在我自己的层中启用 GPU。使用 caffe 的内置层的问题之一是我的函数不能变得太复杂,例如,需要选择满足特定条件的元素的自定义激活层。因此,我正在寻找一种在我的 pycaffe 层中利用 Tensorflow 的自动渐变功能的方法。
    • 我注意到您的实现与我的有些不同。减少会给出形状为 (1,0,0,0) 的结果,但是,我只想拥有通道方向的 L2,它预计会给出形状为 (0,0,W,H) 的结果。跨度>
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-03-07
    • 1970-01-01
    • 2015-08-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多