Tensorflow,如何计算给定前向函数的反向传递

时间:2017-07-24 15:45:32

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

我想用Caffe样式构建一个L2范数层(好吧,我实际上想在Tensorflow层中使用pycaffe,因为使用CUDA来编写.cu中的Caffe个文件是一项繁重的任务。)

正面传球:
- 输入(x):n-D阵列
- 输出(y):具有相同输入形状的n-D阵列
- 操作:

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来计算正向传递函数的渐变?

1 个答案:

答案 0 :(得分:1)

我认为您最好的策略是使用现有的caffe图层来实现您的目标 首先,使用"Reduction"图层计算x

的sq.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"将其返回到与shape相同的x

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 }
}

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