为什么`tf.train.Optimizer()。compute_gradients(loss)`也会返回不在`loss`子图中的变量?

时间:2018-10-22 20:55:37

标签: tensorflow neural-network deep-learning backpropagation

我正在手动收集多任务处理模型的梯度统计信息,该模型的看起来像这样:

input -> [body_var1 ... body_varN] --> [task1_var1 ... task1_varM] <-- loss_1
                                   \-> [task2_var1 ... task2_varM] <-- loss_2

我正在为每种损失定义一个单独的优化器,如下所示(实际代码非常复杂,此问题的简化内容如下):

# for simplicity, just demonstrate the case with the 1st task
task_index = 1

# here we define the optimizer (create an instance in graph)
loss = losses[task_index]
optimizer = tf.train.GradientDescentOptimizer()
grads_and_vars = optimizer.compute_gradients(loss)

# now let's see what it returns
for g, v in grads_and_vars:
    print('  grad:', g, ', var:', v)

因此,上面的代码显然仅为任务1的分支创建了一个单独的优化器,然后我们使用optimizer.compute_gradients(loss)创建了梯度计算操作,并打印了要对其应用梯度的变量。

预期结果

grad: body_var1_grad, var: body_var1    # \
...                                     # --> body vars and gradients
grad: body_varN_grad, var: body_varN    # /
grad: task1_var1_grad, var: task1_var1  # \
...                                     # --> task 1 vars and gradients
grad: task1_var1_grad, var: task1_var1  # /

因此,我希望优化器仅对其应用的分支(即,第一个任务的分支)包含渐变计算操作

实际结果

grad: body_var1_grad, var: body_var1    # \
...                                     # --> body vars and gradients
grad: body_varN_grad, var: body_varN    # /
grad: task1_var1_grad, var: task1_var1  # \
...                                     # --> task 1 vars and gradients
grad: task1_var1_grad, var: task1_var1  # /
grad: None, var: task2_var1             # \
...                                     # --> task 2 vars, with None gradients
grad: None, var: task2_var1             # /

因此,看起来optimizer.compute_gradients(loss)不仅捕获了输出到loss的子图(可以使用tf.graph_util.extract_sub_graph提取),而且还捕获了与{ {1}}而不为其创建渐变变量(因此返回的渐变变量为loss)。

  

问题:这种行为正常吗?

1 个答案:

答案 0 :(得分:2)

是的,是因为compute_gradients()相对于loss对象列表(它传递给tf.Variable参数)计算var_list的梯度。如果未提供var_list,则该函数将针对GraphKeys.TRAINABLE_VARIABLES集合中的所有变量计算梯度。另外,如果loss不依赖于某些变量,则loss相对于那些变量的梯度没有定义,即返回None。根据您提供的代码,情况似乎确实如此。

如果您只希望optimizer仅针对某些变量计算梯度,则应列出此类变量并将其传递给var_list的{​​{1}}参数。