栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Python

pytorch 中的 .detach() .clone()

Python 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

pytorch 中的 .detach() .clone()

  • pytorch tensor 中的 .clone() 和 .detach()

    detach() 的用法

    在写代码时经常能见到通过 tensor.detach().clone() 操作生成一个和原本 tensor 值相同的新 tensor

    为什么需要同时使用 .clone() 和 .detach() ,接下来通过代码进行说明

    1. 生成两个 tensor,并且求梯度

      a = torch.tensor([1.0, 1.0], requires_grad=True)
      b = torch.tensor([2.0, 2.0], requires_grad=True)
      loss = a@b
      loss.backward()
      print(a, b)
      print(a.grad, b.grad)
      

      输出结果:

      tensor([1., 1.], requires_grad=True) tensor([2., 2.], requires_grad=True)
      tensor([2., 2.]) tensor([1., 1.])

      可以看到 a, b 的梯度分别为 [2., 2.],[1., 1.]

    2. 使用 a_=a.detch() 脱离计算图

      在上面的代码中加上 a_=a.detch() 并且使用 a_ 计算和 backward()

      a = torch.tensor([1.0, 1.0], requires_grad=True)
      b = torch.tensor([2.0, 2.0], requires_grad=True)
      a_ = a.detach()
      loss = a_@b
      loss.backward()
      print(a, b)
      print(a.grad, b.grad)
      

      输出结果:

      tensor([1., 1.], requires_grad=True) tensor([2., 2.], requires_grad=True)
      None tensor([1., 1.])

      此时 a 的梯度为 none,因为.detach() 生成了一个新的 tensor 并且从计算图中脱离。a_ 运算后产生的梯度并不会传回 a

      关于 detach()具体细节可以查询官方文档

      生成的 a_ 是不会计算梯度的:

      print(a_.requires_grad)
      # out: False
      
    3. 需要注意的是 .detach() 生成的 tensor 和原本的 tensor 共享内存

      a = torch.tensor([1.0, 1.0], requires_grad=True)
      b = torch.tensor([2.0, 2.0], requires_grad=True)
      a_ = a.detach()
      # 对 a_ 修改
      a_[0] +=2 
      loss = a@b
      loss.backward()
      print(a, b)
      print(a.grad, b.grad)
      

      输出:

      tensor([3., 1.], requires_grad=True) tensor([2., 2.], requires_grad=True)
      tensor([2., 2.]) tensor([3., 1.])

      可以看到 a, b 的梯度分别为 [2., 2.],[3., 1.],原本a, b 的梯度分别为 [2., 2.],[1., 1.],但是因为改变了 a_[0],导致 a[0] 也变了,所以梯度也发生了变化。

      上面的代码中,通过.detach() 生成了新的 tensor,然后修改新生成的 tensor。在计算原本 a@b 的backward() 发现 b 的梯度发生了变化。这是因为修改了 a_ 的同时 a 也发生了变换。所以需要 .clone()

    4. 使用 .clone() 生成新的 tensor

      a = torch.tensor([1.0, 1.0], requires_grad=True)
      b = torch.tensor([2.0, 2.0], requires_grad=True)
      a_ = a.clone()
      a_[0] +=2 
      loss = a@b
      loss.backward()
      print(a, b)
      print(a.grad, b.grad)
      

      输出:

      tensor([1., 1.], requires_grad=True) tensor([2., 2.], requires_grad=True)
      tensor([2., 2.]) tensor([1., 1.])

      上述代码中,a_由a.clone() 生成。对a_ 进行修改并不会影响原本的a

    5. .clone() 和.detach()

      .clone() 生成的 tensor 是可微的,在 backward 时候会将梯度回传

      在官方文档-clone() 中提到

      This function is differentiable, so gradients will flow back from the result of this operation to input. To create a tensor without an autograd relationship to input see detach().

      a = torch.tensor([1.0, 1.0], requires_grad=True)
      b = torch.tensor([2.0, 2.0], requires_grad=True)
      a_ = a.clone()
      a_[0] +=2 
      loss = a_@b
      loss.backward()
      print(a, b)
      print(a.grad, b.grad)
      

      tensor([1., 1.], requires_grad=True) tensor([2., 2.], requires_grad=True)
      tensor([2., 2.]) tensor([3., 1.])

      可以看到,b 的梯度是 [3., 1.] 而不是 [1., 1.]

      这是因为使用 .clone() 生成的 tensor 进行运算,反向求导产生的梯度会传回输入节点。

      所以一般.clone() 和.detach() 需要配合使用

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/953808.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号