我想深入了解一下关于 torch.from_numpy()
工作。
import numpy as np
import torch
arr = np.zeros((3, 3), dtype=np.float32)
t = torch.from_numpy(arr)
print("arr: {0}\nt: {1}\n".format(arr, t))
arr[0,0]=1
print("arr: {0}\nt: {1}\n".format(arr, t))
print("id(arr): {0}\nid(t): {1}".format(id(arr), id(t)))
输出结果是这样的。
arr: [[0. 0. 0.]
[0. 0. 0.]
[0. 0. 0.]]
t: tensor([[0., 0., 0.],
[0., 0., 0.],
[0., 0., 0.]])
arr: [[1. 0. 0.]
[0. 0. 0.]
[0. 0. 0.]]
t: tensor([[1., 0., 0.],
[0., 0., 0.],
[0., 0., 0.]])
id(arr): 2360964353040
id(t): 2360964352984
这是文档的一部分 torch.from_numpy()
:
from_numpy(ndarray) -> Tensor
创建一个:类。
Tensor
从一个:类中创建一个:类。numpy.ndarray
.返回的张量和 :attr.共享同一个内存。
ndarray
共享相同的内存。. 对张量的修改将反映在:attr.中,反之亦然。ndarray
中反映,反之亦然。返回的张量是不可调整大小的。
这是从 id()
:
返回一个物体的身份。
保证在同时存在的对象中是唯一的。 (CPython使用对象的内存地址。)
那么问题来了。由于ndarray arr
和张量 t
共享相同的内存,为什么它们的内存地址不同?
有什么想法建议吗?
是的。t
和 arr
在内存的不同区域是不同的Python对象 (因此不同的 id
),但两者都指向包含数据的同一个内存地址(连续(通常)C数组)。
numpy
对这个区域进行操作,使用 C
绑定代码 Python
职能,同样也是 torch
(但使用 C++
). id()
不知道任何关于数据本身的内存地址,只知道它的 "包装"。
EDIT: 当你分配 b = a
(假设 a
是 np.array
),两者都是对同一个Python封装器的引用(np.ndarray
). 换言之 同名异姓.
这只是Python的赋值方式,见 文件. 以下所有情况都将返回 True
也是。
import torch
import numpy as np
tensor = torch.tensor([1,2,3])
tensor2 = tensor
id(tensor) == id(tensor2)
arr = np.array([1, 2, 3, 4, 5])
arr2 = arr
id(arr) == id(arr2)
some_str = "abba"
other_str = some_str
id(some_str) == id(other_str)
value = 0
value2 = value
id(value) == id(value2)
现在,当你使用 torch.from_numpy
关于 np.ndarray
你有两个不同类的对象(torch.Tensor
和原 np.ndarray
). 由于这些都是不同的类型,它们不可能有相同的。id
. 我们可以把这种情况看作是类似于下面的情况。
value = 3
string_value = str(3)
id(value) == id(string_value)
在这里,直观的是 string_value
和 value
是两个不同的对象,在不同的内存位置。
EDIT 2.Python对象和底层C数组的所有概念必须分开。
总而言之,Python 对象和底层 C 数组的概念必须分开。id()
不知道 C 绑定 (怎么可能?),但它知道 Python 结构的内存地址 (torch.Tensor
, np.ndarray
).
如果是 numpy
和 torch.tensor
你可能会出现以下情况。
torch.from_numpy
)torch.tensor
和另一个 np.array
). 可以通过 from_numpy
其次 clone()
或类似深度复制操作。torch.tensor
对象,一个引用另一个,如上所述)