问题描述
运行程序,出现报错信息 TypeError: can't convert CUDA tensor to numpy. Use Tensor.cpu() to copy the tensor to host memory first.
。
具体信息如下所示:
Traceback (most recent call last):
File "tools/demo.py", line 97, in <module>
visualize_result(gallery_img, detections, similarities)
File "tools/demo.py", line 41, in visualize_result
(x1, y1), x2 - x1, y2 - y1, fill=False, edgecolor="#4CAF50", linewidth=3.5
File "/environment/miniconda3/lib/python3.7/site-packages/matplotlib/axes/_base.py", line 2358, in add_patch
self._update_patch_limits(p)
File "/environment/miniconda3/lib/python3.7/site-packages/matplotlib/axes/_base.py", line 2381, in _update_patch_limits
patch_trf = patch.get_transform()
File "/environment/miniconda3/lib/python3.7/site-packages/matplotlib/patches.py", line 278, in get_transform
return self.get_patch_transform() + artist.Artist.get_transform(self)
File "/environment/miniconda3/lib/python3.7/site-packages/matplotlib/patches.py", line 752, in get_patch_transform
bbox = self.get_bbox()
File "/environment/miniconda3/lib/python3.7/site-packages/matplotlib/patches.py", line 845, in get_bbox
return transforms.Bbox.from_extents(x0, y0, x1, y1)
File "/environment/miniconda3/lib/python3.7/site-packages/matplotlib/transforms.py", line 839, in from_extents
bbox = Bbox(np.reshape(args, (2, 2)))
File "<__array_function__ internals>", line 6, in reshape
File "/home/featurize/work/.local/lib/python3.7/site-packages/numpy/core/fromnumeric.py", line 298, in reshape
return _wrapfunc(a, 'reshape', newshape, order=order)
File "/home/featurize/work/.local/lib/python3.7/site-packages/numpy/core/fromnumeric.py", line 54, in _wrapfunc
return _wrapit(obj, method, *args, **kwds)
File "/home/featurize/work/.local/lib/python3.7/site-packages/numpy/core/fromnumeric.py", line 43, in _wrapit
result = getattr(asarray(obj), method)(*args, **kwds)
File "/home/featurize/work/.local/lib/python3.7/site-packages/torch/tensor.py", line 458, in __array__
return self.numpy()
TypeError: can't convert CUDA tensor to numpy. Use Tensor.cpu() to copy the tensor to host memory first.
解决办法
这个问题是由 python 3.7 版本引起的。修改部分 python 源码即可。
根据报错信息,定位到 /home/featurize/work/.local/lib/python3.7/site-packages/torch/tensor.py
将 self.numpy() 改成 self.cpu().numpy(),即找到 tensor.py 的第 458 行
def __array__(self, dtype=None):
if dtype is None:
return self.numpy()
else:
return self.numpy().astype(dtype, copy=False)
改成
def __array__(self, dtype=None):
if dtype is None:
return self.cpu().numpy()
else:
return self.cpu().numpy().astype(dtype, copy=False)
使用 vim 修改
- 如果服务器上装有 vim,可以使用 vim 打开 tensor.py 文件
cd /home/featurize/work/.local/lib/python3.7/site-packages/torch
vim tensor.py
- 在 vim 中键入
/numpy
搜索numpy
,输入 n 向下搜索,N 向上搜索 - 输入 i 切换到编辑模式,进行修改
- 修改完成,使用 Esc 键切换到普通模式。输入
:wq
保存 tensor.py 文件并退出 vim
使用 Jupyter notebook
如果使用 notebook 运行代码,如 colab 环境下,则可以使用魔术命令修改 tensor.py 文件。
- 首先切换到 tensor.py 所在目录下
cd /home/featurize/work/.local/lib/python3.7/site-packages/torch
注意:colab 的 tensor 在 usr/local/lib/python3.7/dist-packages/torch
- 使用
%pycat tensor.py
打开 tensor.py 文件 - 复制 tensor.py 中的所有代码到一个单元格中,将 self.numpy() 改成 self.cpu().numpy()
- 移除原有 tensor.py 文件
!rm tensor.py
- 在单元格的开头加入
%%writefile tensor.py
,运行单元格生成新的 tensor.py 文件。再次运行就不会报错。
当然,也可以直接切换到 tensor.py 所在目录下。把下面我修改好的代码复制到一个单元格中,运行单元格写入修改过的 tensor.py 文件。跳过上面的步骤 2-5 。
%%writefile tensor.py
import sys
import torch
import torch._C as _C
from collections import OrderedDict
import torch.utils.hooks as hooks
import warnings
import weakref
from torch._six import imap
from torch._C import _add_docstr
from numbers import Number
# NB: If you subclass Tensor, and want to share the subclassed class
# across processes, you must also update torch/multiprocessing/reductions.py
# to define a ForkingPickler serialization mode for the class.
#
# NB: If you add a new method to Tensor, you must update
# torch/__init__.py.in to add a type annotation for your method;
# otherwise, it will not show up in autocomplete.
class Tensor(torch._C._TensorBase):
def __deepcopy__(self, memo):
if not self.is_leaf:
raise RuntimeError("Only Tensors created explicitly by the user "
"(graph leaves) support the deepcopy protocol at the moment")
if id(self) in memo:
return memo[id(self)]
with torch.no_grad():
if self.is_sparse:
new_tensor = self.clone()
else:
new_storage = self.storage().__deepcopy__(memo)
new_tensor = self.new()
new_tensor.set_(new_storage, self.storage_offset(), self.size(), self.stride())
memo[id(self)] = new_tensor
new_tensor.requires_grad = self.requires_grad
return new_tensor
def __reduce_ex__(self, proto):
# See Note [Don't serialize hooks]
torch.utils.hooks.warn_if_has_hooks(self)
args = (self.storage(),
self.storage_offset(),
tuple(self.size(