torch可以成功引用但无法访问属性

运行程序时遇到了一个奇怪的报错:

# ... 省略 ...
AttributeError: module 'torch' has no attribute 'Tensor'

意思是模块torch没有Tensor属性。这是比较奇怪的一件事,因为torch肯定是可以访问Tensor。

后来在stackoverflow上找到了一个类似的错误,底下有人回复说这是因为python在执行import torch时引入的并不是torch包,而是一个命名空间(对应一个名为torch的文件夹)。

验证

首先查看一下是不是torch的引用真的有问题:

$ python
>>> import torch
>>> torch.Tensor
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: module 'torch' has no attribute 'Tensor'
>>> torch.nn
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: module 'torch' has no attribute 'nn'

引入torch没有问题,但是不仅不能访问Tensor,连nn也不能访问。这说明我们的确引入了一个错误的torch。

>>> print(torch)
<module 'torch' (namespace)>
>>> print(torch.__path__)
_NamespacePath(['.../python3.8/site-packages/torch'])

果然,这个torch不是我们期望的torch,而是一个命名空间,而且我们也可以定位到问题所在的路径。

解决

沿着路径找下去,的确有一个名为torch的目录,其中包含很多东西,应该是正常torch所需要的那些。但是其中没有__init.py__,不知道是什么原因导致的。

位于模块搜索路径上的任何不存在 __init__.py 文件的目录都将被视为命名空间。
(在搜索路径的其他任何位置都没有同名模块或包)

所以,在torch目录下创建一个__init__.py是不是就好啦?
我没有选择这样做,因为我不确定torch目录下的其他文件是不是完好的。我选择删除掉这个 torch目录,然后pip重新安装torch。最后问题成功解决。
当然,也有可能你本身是有正确的torch包,只不过有了额外的名为torch的目录导致这个问题。那你可以选择将目录改名来规避该问题。

结果

重新安装torch后,再测试一下。这回对了,python清楚地知道这是一个package,而不是一个namespace。

>>> import torch
>>> print(torch)
<module 'torch' from '.../lib/python3.8/site-packages/torch/__init__.py'>
>>> print(torch.__path__)
['.../lib/python3.8/site-packages/torch']