解决使用copy.deepcopy()拷贝Tensor或model时报错只支持用户显式创建的Tensor问题

这篇具有很好参考价值的文章主要介绍了解决使用copy.deepcopy()拷贝Tensor或model时报错只支持用户显式创建的Tensor问题。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

模型训练过程中常需边训练边做validation或在训练完的模型需要做测试,通常的做法当然是先创建model实例然后掉用load_state_dict()装载训练出来的权重到model里再调用model.eval()把模型转为测试模式,这样写对于训练完专门做测试时当然是比较合适的,但是对于边训练边做validation使用这种方式就需要写一堆代码,如果能使用copy.deepcopy()直接深度拷贝训练中的model用来做validation显然是比较简洁的写法,但是由于copy.deepcopy()的限制,写model里代码时如果没注意,调用copy.deepcopy(model)时可能就会遇到这个错误:Only Tensors created explicitly by the user (graph leaves) support the deepcopy protocol at the moment,详细错误信息如下:

 File "/usr/local/lib/python3.6/site-packages/prc/framework/model/validation.py", line 147, in init_val_model
    val_model = copy.deepcopy(model)
  File "/usr/lib64/python3.6/copy.py", line 180, in deepcopy
    y = _reconstruct(x, memo, *rv)
  File "/usr/lib64/python3.6/copy.py", line 280, in _reconstruct
    state = deepcopy(state, memo)
  File "/usr/lib64/python3.6/copy.py", line 150, in deepcopy
    y = copier(x, memo)
  File "/usr/lib64/python3.6/copy.py", line 240, in _deepcopy_dict
    y[deepcopy(key, memo)] = deepcopy(value, memo)
  File "/usr/lib64/python3.6/copy.py", line 180, in deepcopy
    y = _reconstruct(x, memo, *rv)
  File "/usr/lib64/python3.6/copy.py", line 306, in _reconstruct
    value = deepcopy(value, memo)
  File "/usr/lib64/python3.6/copy.py", line 180, in deepcopy
    y = _reconstruct(x, memo, *rv)
  File "/usr/lib64/python3.6/copy.py", line 280, in _reconstruct
    state = deepcopy(state, memo)
  File "/usr/lib64/python3.6/copy.py", line 150, in deepcopy
    y = copier(x, memo)
  File "/usr/lib64/python3.6/copy.py", line 240, in _deepcopy_dict
    y[deepcopy(key, memo)] = deepcopy(value, memo)
  File "/usr/lib64/python3.6/copy.py", line 180, in deepcopy
    y = _reconstruct(x, memo, *rv)
  File "/usr/lib64/python3.6/copy.py", line 306, in _reconstruct
    value = deepcopy(value, memo)
  File "/usr/lib64/python3.6/copy.py", line 180, in deepcopy
    y = _reconstruct(x, memo, *rv)
  File "/usr/lib64/python3.6/copy.py", line 280, in _reconstruct
    state = deepcopy(state, memo)
  File "/usr/lib64/python3.6/copy.py", line 150, in deepcopy
    y = copier(x, memo)
  File "/usr/lib64/python3.6/copy.py", line 240, in _deepcopy_dict
    y[deepcopy(key, memo)] = deepcopy(value, memo)
  File "/usr/lib64/python3.6/copy.py", line 161, in deepcopy
    y = copier(memo)
  File "/root/.local/lib/python3.6/site-packages/torch/_tensor.py", line 55, in __deepcopy__
    raise RuntimeError("Only Tensors created explicitly by the user "
RuntimeError: Only Tensors created explicitly by the user (graph leaves) support the deepcopy protocol at the moment

这个错误简单地说就是copy.deepcopy()不支持拷贝requires_grad=True的Tensor(在网络中一般是非叶子结点Tensor, grad_fn不为None),开始以为真的哪个地方Tensor的requires_grad没有按要求设置,熬了几个夜去检查调试网络代码没发现什么线索很郁闷,后来想既然是copy.deepcopy()里报错的,源码也有那就去它里面debug看是拷贝网络的那部分时抛出的Exception吧,折腾了一阵发现里面这个地方加breakpoint比较合适:

   if dictiter is not None:
        if deep:
            for key, value in dictiter:
                key = deepcopy(key, memo)
                value = deepcopy(value, memo)
                y[key] = value
        else:
            for key, value in dictiter:
                y[key] = value

我这个网络的结构是使用的python dict方式定义的,运行时使用注册机制动态创建出来的,既然是dict,这里的key和value就是对应配置文件里的定义网络每层结构的dict的key和value,在这里加bp可以比较清楚地跟踪看到是在哪个地方导致的抛出Exception,结果发现原因是因为有个实现分割功能的head类的内部有个成员变量保存了这层的输出结果Tensor用于后面计算loss,模型每层的输出数据Tensor自然是requires_grad=True,把这个成员变量去掉,改成forward()输出结果,然后在网络的主类里接收它并传入计算Loss的函数,然后deepcopy(model)就不报上面的错了!

另外,显式创建一个Tensor时指定requires_grad=True(默认是False)并不会导致copy.deepcopy()报错,不管这个Tensor是在cpu上还是gpu上,关键是用户自己创建的Tensor是叶子结点Tensor,它的grad_fn是None,在这个Tensor上做切片或者加载到gpu上等操作得到的新的Tensor就不是叶子结点了,pytorch认为requires_grad=Trued的Tensor经过运算得到新的Tensor是需要求导的会自动加上grad_fn而不管这个Tensor是不是网络的一部分,这时再使用copy.deepcopy()深度拷贝新的Tensor时会抛出上面的错误,看完下面的示例就知道了:

>>> t = torch.tensor([1,2,3.5],dtype=torch.float32, requires_grad=True, device='cuda:0')
>>> t
tensor([1.0000, 2.0000, 3.5000], device='cuda:0', requires_grad=True)
>>> x = copy.deepcopy(t)
>>> x
tensor([1.0000, 2.0000, 3.5000], device='cuda:0', requires_grad=True)
>>> t1 = t[:2]
>>> t1
tensor([1., 2.], device='cuda:0', grad_fn=<SliceBackward0>)
>>> x = copy.deepcopy(t1)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/local/python3.8/lib/python3.8/copy.py", line 153, in deepcopy
    y = copier(memo)
  File "/root/.local/lib/python3.8/site-packages/torch/_tensor.py", line 85, in __deepcopy__
    raise RuntimeError("Only Tensors created explicitly by the user "
RuntimeError: Only Tensors created explicitly by the user (graph leaves) support the deepcopy protocol at the moment

>>> t = torch.tensor([1,2,3.5],dtype=torch.float32, requires_grad=True)
>>> t1 = t.cuda()
>>> t1
tensor([1.0000, 2.0000, 3.5000], device='cuda:0', grad_fn=<ToCopyBackward0>)
>>> x = copy.deepcopy(t1)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/local/python3.8/lib/python3.8/copy.py", line 153, in deepcopy
    y = copier(memo)
  File "/root/.local/lib/python3.8/site-packages/torch/_tensor.py", line 85, in __deepcopy__
    raise RuntimeError("Only Tensors created explicitly by the user "
RuntimeError: Only Tensors created explicitly by the user (graph leaves) support the deepcopy protocol at the moment

>>> t = torch.tensor([1,2,3.5],dtype=torch.float32, requires_grad=False)
>>> t
tensor([1.0000, 2.0000, 3.5000])
>>> x = copy.deepcopy(t)
>>> x
tensor([1.0000, 2.0000, 3.5000])
>>> t1 = t[:2]  
>>> t1
tensor([1., 2.])
>>> x = copy.deepcopy(t1)

为何deepcopy()不直接支持有梯度的Tensor,按理要支持复制一个当时的瞬间值应该也没问题,看到https://discuss.pytorch.org/t/copy-deepcopy-vs-clone/55022/10这里这个经常回答问题的胡子哥给了个猜测:文章来源地址https://www.toymoban.com/news/detail-802331.html

runtimeerror: only tensors created explicitly by the user (graph leaves) sup,python,deepcopy,Tensor,requires_grad,grad_fn,Powered by 金山文档
runtimeerror: only tensors created explicitly by the user (graph leaves) sup,python,deepcopy,Tensor,requires_grad,grad_fn,Powered by 金山文档

到了这里,关于解决使用copy.deepcopy()拷贝Tensor或model时报错只支持用户显式创建的Tensor问题的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Python - 拷贝 - 浅拷贝(Shallow Copy)和深拷贝(Deep Copy)

    假设我以这样的方式创建一个 3 x 5 的二维数组: 然后我修改 a [ 2 ] [ 3 ] a[2][3] a [ 2 ] [ 3 ] 的值为 1 1 1 : 结果会发现数组 a a a 中第二维坐标为 3 3 3 的数全部被修改为了 1 1 1 ,而没有发生“第一维坐标为 2 2 2 的数全部被改成了 1 1 1 ” 这就涉及到了Python中的拷贝机制。 Python中

    2023年04月08日
    浏览(27)
  • TypeError: can‘t convert cuda:0 device type tensor to numpy. Use Tensor.cpu() to copy the tensor to

    在用GPU训练模型时报如下的错误: TypeError: can’t convert cuda:0 device type tensor to numpy. Use Tensor.cpu() to copy the tensor to host memory first. GPU上的tensor张量无法转为numpy格式,那我们把它转到CPU上即可。 方法非常简单,只需在目标张量后面加 .cpu() 即可。 Before: After:

    2024年02月12日
    浏览(36)
  • Dockerfile 指令 COPY 拷贝文件夹

    网上查了查资料,这里记录一下。         今天在编写 dockerfile 时使用 COPY 拷贝文件夹时遇到了意料之外的情况。在此记录一下正确的使用方法。         今天在通过 dockerfile 将文件夹拷贝到镜像的时候发现,是把文件夹下的内容拷贝进去了。 dockerfile 如下:     

    2024年01月18日
    浏览(41)
  • Kafka的零拷贝技术Zero-Copy

    流程步骤: (1)操作系统将数据从磁盘文件中读取到内核空间的页面缓存; (2)应用程序将数据从内核空间读入用户空间缓冲区; (3)应用程序将读到数据写回内核空间并放入socket缓冲区; (4)操作系统将数据从socket缓冲区复制到网卡接口,此时数据才能通过网络发送

    2024年02月08日
    浏览(31)
  • Secure Copy Protocol or SCP - 安全拷贝协议

    Secure Copy (remote file copy program) The SCP program is a software tool implementing the SCP protocol as a service daemon or client. It is a program to perform secure copying. The SCP server program is typically the same program as the SCP client. The SCP Server software can be installed on a Regular Machine and be configured to only accept SCP Traffic on

    2024年04月14日
    浏览(35)
  • C++ 惯用法之 Copy-Swap 拷贝交换

    这是“C++ 惯用法”合集的第 3 篇,前面 2 篇分别介绍了 RAII 和 PIMPL 两种惯用法: RAII: Resouce Acquistion Is Initialization PIMPL:Pointer To Implemetation 正式介绍 Copy-Swap 之前,先看下《剑指 Offer》里的第☝️题: 如下为类型 CMyString 的声明,请为该类型添加赋值运算符函数。 这道题目虽

    2024年02月13日
    浏览(26)
  • 警告UserWarning: To copy construct from a tensor, it is recommended to use sourceTensor.clone().detach

    这个警告信息是提示在构造新的张量时,推荐使用  sourceTensor.clone().detach()  或  sourceTensor.clone().detach().requires_grad_(True) ,而不是使用  torch.tensor(sourceTensor)  的方式。 警告信息提到了这个建议,是因为在 PyTorch 中, torch.tensor()  函数都会创建新的张量,并且不与原先的张量

    2024年02月16日
    浏览(36)
  • H.266/VVC SCC技术学习:帧内块拷贝(Intra block copy, IBC)

    帧内块拷贝 (Intra block copy, IBC) 是 HEVC 针对屏幕内容编码(Screen content coding)序列的扩展工具,它显着提高了屏幕内容序列的编码效率。 IBC 是一种块级编码模式, IBC 编码的 CU 被视为除帧内或帧间预测模式之外的第三预测模式。和帧间技术类似,编码端执行运动搜索( 块匹

    2023年04月22日
    浏览(20)
  • pytorch model代码内tensor device不一致的问题

    在编写一段处理两个tensor的代码如下,需要在forward函数内编写函数创建一个新的tensor进行索引的掩码计算 这段代码报了这个错误 统一下进行掩码计算的张量的设备即可

    2024年02月13日
    浏览(29)
  • 【四】3D Object Model之创建Creation——clear_object_model_3d()/copy_object_model_3d()算子

    😊😊😊 欢迎来到本博客 😊😊😊 🌟🌟🌟 Halcon算子太多,学习查找都没有系统的学习查找路径,本专栏主要分享Halcon各类算子含义及用法,有时间会更新具体案例。 😊😊😊 具体食用方式:可以点击本专栏【Halcon算子快速查找】–搜索你要查询的算子名称;或者点击

    2024年02月11日
    浏览(27)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包