为什么 `tf.train.Optimizer().compute_gradients(loss)` 也 returns 变量不在 `loss` 的子图中?
Why `tf.train.Optimizer().compute_gradients(loss)` also returns variables not in the subgraph of `loss`?
我正在手动收集 Multi-Tasking 模型的梯度统计数据,graph 的示意图如下所示:
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
提取),而且还捕获连接的所有可训练变量到 loss
而不为它们创建梯度变量(因此返回的梯度变量是 None
)。
Question: is such behavior normal?
是的,是的,因为 compute_gradients() computes gradients of loss
with respect to a list of tf.Variable
objects which is passed to the var_list
parameter. If var_list
is not provided, the function calculates gradients with respect to all variables from GraphKeys.TRAINABLE_VARIABLES collection。此外,如果 loss
不依赖于某些变量,则 loss
相对于这些变量的梯度未定义,即返回 None
。根据您提供的代码,情况似乎是这样。
如果您希望 optimizer
仅针对某些变量计算梯度,您应该列出此类变量并将其传递给 compute_gradients()
的 var_list
参数。
我正在手动收集 Multi-Tasking 模型的梯度统计数据,graph 的示意图如下所示:
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
提取),而且还捕获连接的所有可训练变量到 loss
而不为它们创建梯度变量(因此返回的梯度变量是 None
)。
Question: is such behavior normal?
是的,是的,因为 compute_gradients() computes gradients of loss
with respect to a list of tf.Variable
objects which is passed to the var_list
parameter. If var_list
is not provided, the function calculates gradients with respect to all variables from GraphKeys.TRAINABLE_VARIABLES collection。此外,如果 loss
不依赖于某些变量,则 loss
相对于这些变量的梯度未定义,即返回 None
。根据您提供的代码,情况似乎是这样。
如果您希望 optimizer
仅针对某些变量计算梯度,您应该列出此类变量并将其传递给 compute_gradients()
的 var_list
参数。