Tensorflow,如何计算给定前向函数的后向传递
Tensorflow, How can I compute backward pass for a given forward function
我想构建一个 Caffe
样式的 L2 范数层(好吧,我实际上想在 pycaffe
层中使用 Tensorflow
,因为使用 CUDA
在 Caffe
中写入 .cu
个文件是一项繁重的任务。)
前传:
- 输入(x):n维数组
- output(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
自动计算前向传递函数的梯度?
我认为你最好的策略是使用现有的 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"
将其恢复为与 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. 您可能还会发现 有用。
我想构建一个 Caffe
样式的 L2 范数层(好吧,我实际上想在 pycaffe
层中使用 Tensorflow
,因为使用 CUDA
在 Caffe
中写入 .cu
个文件是一项繁重的任务。)
前传:
- 输入(x):n维数组
- output(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
自动计算前向传递函数的梯度?
我认为你最好的策略是使用现有的 caffe 层来实现你的目标。
首先,使用 "Reduction"
层计算 x
:
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. 您可能还会发现