Python tf.nn.conv2d_backprop_滤波器的奇怪结果

Python tf.nn.conv2d_backprop_滤波器的奇怪结果,python,tensorflow,deep-learning,convolution,Python,Tensorflow,Deep Learning,Convolution,以下代码用于检查tensorflow中CNN的conv2d内核(过滤器)权重的反向传播过程。 首先,我获取conv2d的输出,以检查输入的哪些元素用于生成输出。 使用3X3输入、1X1内核和stride 3调用tf.conv2d。 接下来,在假设conv输出的梯度为[[100]]的情况下,我使用tf.nn.conv2d_backprop_过滤器函数获得了内核梯度 import tensorflow as tf import numpy as np x = tf.placeholder("flo

以下代码用于检查tensorflow中CNN的conv2d内核(过滤器)权重的反向传播过程。 首先,我获取conv2d的输出,以检查输入的哪些元素用于生成输出。 使用3X3输入、1X1内核和stride 3调用tf.conv2d。 接下来,在假设conv输出的梯度为[[100]]的情况下,我使用tf.nn.conv2d_backprop_过滤器函数获得了内核梯度

import tensorflow as tf
import numpy as np

x = tf.placeholder("float", [1,3,3,1])
k = tf.placeholder("float", [1,1,1,1])
g = tf.placeholder("float", [1,1,1,1])

tfconv = tf.nn.conv2d(x, k, strides=[1,3,3,1], padding='SAME', data_format='NHWC')
tfgrad = tf.nn.conv2d_backprop_filter(x, [1,1,1,1], g, strides=[1,3,3,1], padding='SAME', data_format='NHWC')

input = np.array([1,2,3,4,5,6,7,8,0]).reshape(1,3,3,1)
kernel = np.array([10]).reshape(1,1,1,1)
gradient = np.array([100]).reshape(1,1,1,1)

with tf.Session() as sess:
    sess.run(tf.global_variables_initializer())
    conv_tf = sess.run(tfconv, feed_dict={x:input, k:kernel})
    grad_tf = sess.run(tfgrad, feed_dict={x:input, g:gradient})

    print("inp = {}".format(input[0,:,:,0]))
    print("kernel = {}".format(kernel[:,:,0,0]))
    print("conv_tf = {}".format(conv_tf[0,:,:,0]))
    print("gradient = {}".format(gradient[0,:,:,0]))
    print("grad_tf = {}".format(grad_tf[0,:,:,0]))
输出如下所示

inp = [[1 2 3]
       [4 5 6]
       [7 8 0]]
kernel = [[10]]
conv_tf = [[50.]]
gradient = [[100]]
grad_tf = [[100.]]
在该测试中,我们可以发现grad_tf是使用位置(0,0)处的输入元素1计算的,而不是conv2d评估中使用的位置(1,1)处的5。 我猜这是tensorflow的一个错误。 当然,这可能是我的错误。 你能告诉我这个问题的原因吗

我发现这个问题会让CNN的培训过程非常混乱,就像下面的案例一样

import tensorflow as tf
import numpy as np

x = tf.placeholder("float", [1,3,3,1])

k_value = [10]
k_init = tf.constant_initializer(k_value)
k = tf.get_variable('k', shape=[1,1,1,1], initializer=k_init)

tfconv = tf.nn.conv2d(x, k, strides=[1,3,3,1], padding='SAME', data_format='NHWC')
cost = tf.reduce_sum(tf.square(tfconv))

train_op = tf.train.GradientDescentOptimizer(learning_rate=0.01).minimize(cost)

ocg = tf.gradients(cost, tfconv)
wcg = tf.gradients(cost, k)
wog = tf.gradients(tfconv, k)

input = np.array([1,2,3,4,5,6,7,8,0], dtype="float32").reshape(1,3,3,1)

with tf.Session() as sess:
    sess.run(tf.global_variables_initializer())

    kv = sess.run(k)
    print("kernel before training = {}".format(kv[:,:,0,0]))

    cv, xv, kv, fv, g1, g2, g3, _ = sess.run([cost, x, k, tfconv, ocg, wcg, wog, train_op], feed_dict={x:input})

    print("cost = {}".format(cv))
    print("x = {}".format(xv[0,:,:,0]))
    print("conv = {}".format(fv[0,:,:,0]))
    print("conv-cost gradient = {}".format(np.asarray(g1)))
    print("kernel-cost gradient = {}".format(np.asarray(g2)))
    print("conv-cost gradient = {}".format(np.asarray(g3)))

    kv = sess.run(k)
    print("kernel after training = {}".format(kv[:,:,0,0]))
下面是输出,重要的是内核权重确实根据错误的输入值进行了更改,该输入值在conv2d操作中未使用,而不是正确的输入值

kernel before training = [[ 10.]]
cost = 2500.0
x = [[ 1.  2.  3.]
 [ 4.  5.  6.]
 [ 7.  8.  0.]]
conv = [[ 50.]]
conv-cost gradient = [[[[[ 100.]]]]]
kernel-cost gradient = [[[[[ 100.]]]]]
conv-cost gradient = [[[[[ 1.]]]]]
kernel after training = [[ 9.]]

我试图理解这个问题,但有些困惑。请您解释一下:“我们可以发现grad_tf是使用位置(0,0)处的输入元素1计算的,而不是conv2d评估中使用的位置(1,1)处的5计算的。”,这是什么意思?感谢您的关注,用户3480922。核权重10乘以输入张量的某个元素,我们很容易知道它在输入的中心是5,因为乘积是50。因此,粒重10的梯度应该是500,这是5和100的乘积。但由于产品是100,如grad_tf.nn所示。conv2d_backprop_过滤器使用输入中左上角的元素1来计算内核权重梯度。我试图理解查询,但有一些困惑。请您解释一下:“我们可以发现grad_tf是使用位置(0,0)处的输入元素1计算的,而不是conv2d评估中使用的位置(1,1)处的5计算的。”,这是什么意思?感谢您的关注,用户3480922。核权重10乘以输入张量的某个元素,我们很容易知道它在输入的中心是5,因为乘积是50。因此,粒重10的梯度应该是500,这是5和100的乘积。但由于乘积为100,如grad_tf.nn所示。conv2d_backprop_过滤器使用输入中的左上角元素1来评估核权重梯度。