【问题标题】:Pytorch memory model: how does "torch.from_numpy()" work? [duplicate]Pytorch 内存模型:“torch.from_numpy()”如何工作? [复制]
【发布时间】:2020-05-01 21:15:30
【问题描述】:

我正在尝试深入了解 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) -> 张量

从 :class:numpy.ndarray 创建一个 :class:Tensor

返回的张量和 :attr:ndarray 共享相同的内存。修改为 张量将反映在 :attr:ndarray 中,反之亦然。返回的 张量不可调整大小。

这是来自id()的文档:

返回对象的标识。

这保证在同时存在的对象中是唯一的。 (CPython 使用对象的内存地址。

那么问题来了: 既然ndarrayarr和张量t共享同一个内存,为什么它们的内存地址不同呢?

有什么想法/建议吗?

【问题讨论】:

    标签: numpy pytorch shared-memory


    【解决方案1】:

    是的,tarr 是位于不同内存区域的不同 Python 对象(因此不同的id)但都指向包含数据的相同内存地址(连续(通常)C 数组)。

    numpy 使用绑定到Python 函数的C 代码在该区域上运行,torch 也是如此(但使用C++)。 id() 对数据本身的内存地址一无所知,只知道它是“包装器”。

    编辑:当您分配 b = a(假设 anp.array)时,两者都是对同一个 Python 包装器 (np.ndarray) 的引用。换句话说,它们是同一个对象,但名称不同

    这就是 Python 的赋值方式,请参阅 documentation。以下所有情况也将返回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)
    

    现在,当您在 np.ndarray 上使用 torch.from_numpy 时,您有两个不同类的对象(torch.Tensor 和原始 np.ndarray)。由于它们的类型不同,它们不能具有相同的id。可以将此案例视为类似于以下案例:

    value = 3
    string_value = str(3)
    
    id(value) == id(string_value)
    

    这里很直观,string_valuevalue 是位于不同内存位置的两个不同对象。

    编辑 2:

    Python 对象和底层 C 数组的所有概念都必须分开。 id() 不知道 C 绑定(怎么可能?),但它知道 Python 结构的内存地址(torch.Tensornp.ndarray)。

    如果是numpytorch.tensor,你可能有以下情况:

    • 在 Python 级别上分开,但对数组使用相同的内存区域 (torch.from_numpy)
    • 在 Python 级别和底层内存区域(一个torch.tensor 和另一个np.array)上分开。可以由from_numpy 后跟clone() 或类似深拷贝操作创建。
    • 在 Python 级别和底层内存区域上相同(例如,两个 torch.tensor 对象,一个引用另一个如上所述)

    【讨论】:

    • 你的意思是id ()只知道变量arrt的内存地址?但是,如果您创建一个像a = np.array([1, 2, 3]) 这样的ndarray,然后将其分配给b,b = a,为什么id() 对它们的行为相同?我还是一头雾水,你能详细解释一下吗?
    猜你喜欢
    • 2018-07-07
    • 2018-04-12
    • 2021-06-23
    • 2019-11-19
    • 2018-08-23
    • 2022-08-15
    • 2022-10-09
    • 1970-01-01
    • 2019-07-25
    相关资源
    最近更新 更多