我试图更深入地理解Tensorflow计算图是如何运作的。假设我们有以下代码:
A = tf.truncated_normal(shape=(1, ), stddev=0.1)B = tf.Variable([0.3], dtype=tf.float32)C = A * Bgrads = tf.gradients(C, [A, B])init = tf.global_variables_initializer()sess = tf.Session()sess.run(init)for i in range(1000): results = sess.run([C, grads], {A: [2], B:[5]})
我得到的结果是10,A的梯度为5,B的梯度为2,这与预期相符。我想确认的是,当我们像对A和B那样向张量输入值时,它们在计算图中定义的默认值生成机制会被覆盖,对吗?
例如,在这里,A不会生成正常的随机值,而是被2覆盖,B的0.3被5替换,每次我们在for循环中运行sess.run
行时都是如此。在这种情况下,计算图的具体行为是怎样的?
对于一般情况,我的理解是否正确:每次调用sess.run
时,会根据拓扑顺序确定计算提取列表中值所需的节点,并且所有张量都会被feed_dict参数中提供的值覆盖,从而打破它们对计算图其余部分的依赖。(例如,如果张量A等待B的值被评估,并且我们在feed_dict中注入一个值到A,那么A对B的依赖就会被打破,我相信这也会在计算图中以某种方式反映出来)。然后,根据计算图的最终形式,执行前向和后向计算。
回答:
我认为只需要做两个小的修正:
-
不是进行两次传递 – 首先确定要执行的最小图,然后“打破它”,而是可以在一次传递中完成 – 考虑到feed dict中的内容,寻找执行sess.run操作所需的最小图。换句话说,每次你发现一个新节点(当你通过操作的依赖关系向后追溯时),你会检查它是否在feed_dict中提供,如果是的话 – 你假设这是给定的,一个叶节点。
-
在TensorFlow中没有“后向计算”这种东西,一切都是前向计算。tf.gradients(或minimize)调用只是构建了一个前向图,它在功能上等同于在许多其他库中在后向传递期间会发生什么。虽然在TensorFlow中没有严格的前向/后向分离 – 你可以自由地修改、混合并对图进行任何你想要的操作 – 最终这些只是相互依赖的节点,具有单向数据流。