torch.no_grad() 和 detach() 合并

torch.no_grad() and detach() combined

我在选择动作时遇到了很多代码片段,如下所示,其中混合了 torch.no_graddetach(其中 actor 是某个演员,SomeDistribution您的首选发行版),我想知道它们是否有意义:

def f():
    with torch.no_grad():
        x = actor(observation)
    dist = SomeDistribution(x)
    sample = dist.sample()
    return sample.detach()

是否在 return 语句中使用 detach 不是不必要的,因为 x 的 requires_grad 已经设置为 False,所以所有使用 x 的计算应该已经脱离图形?或者在 torch.no_grad 包装器之后的计算以某种方式再次出现在图表上,所以我们需要在最后再次分离它们(在我看来,在这种情况下 no_grad 是不必要的)? 另外,如果我是对的,我想除了省略 detach 之外,还可以省略 torch.no_grad,并以相同的功能结束,但性能更差,因此 torch.no_grad 是首选?

虽然它可能是多余的,但它取决于 actorSomeDistribution 的内部结构。通常,我可以想到三种情况,在此代码中 detach 是必需的。由于您已经观察到 x 已将 requires_grad 设置为 False,因此情况 2 和 3 不适用于您的具体情况。

  1. 如果 SomeDistribution 有内部参数(带有 requires_grad=True 的叶张量),那么 dist.sample() 可能会导致计算图将 sample 连接到这些参数。如果不分离,计算图(包括那些参数)将在 returning 之后不必要地保留在内存中。
  2. torch.no_grad 上下文中的默认行为是 return 将 requires_grad 设置为 False 的张量运算的结果。但是,如果 actor(observation) 由于某种原因在 returning 之前明确地将其 return 值的 requires_grad 设置为 True,则可以创建一个计算图来连接 xsample。如果不分离,计算图(包括 x)将在 returning 后不必要地保留在内存中。
  3. 这个似乎更不可能,但如果 actor(observation) 实际上只是 return 对 observation 的引用,而 observation.requires_gradTrue,那么从observationsample的计算图可以在dist.sample().
  4. 期间构建

关于去掉[=12=的leu中的no_grad上下文的建议,这可能会导致构建连接observation的计算图(如果需要梯度的话)and/or 分配的参数(如果有的话)到x。该图将在 detach 后被丢弃,但创建计算图确实需要时间和内存,因此可能会降低性能。

总而言之,no_graddetach 两者都做更安全,但其中任何一个的必要性取决于分布和参与者的细节。