我正在手动收集多任务处理模型的梯度统计信息,该模型的图看起来像这样:
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
)。
问题:这种行为正常吗?
答案 0 :(得分:2)
是的,是因为compute_gradients()相对于loss
对象列表(它传递给tf.Variable
参数)计算var_list
的梯度。如果未提供var_list
,则该函数将针对GraphKeys.TRAINABLE_VARIABLES集合中的所有变量计算梯度。另外,如果loss
不依赖于某些变量,则loss
相对于那些变量的梯度没有定义,即返回None
。根据您提供的代码,情况似乎确实如此。
如果您只希望optimizer
仅针对某些变量计算梯度,则应列出此类变量并将其传递给var_list
的{{1}}参数。