Python PyTorch内存模型:“;torch.from“u numpy()”;vs";torch.Tensor();

Python PyTorch内存模型:“;torch.from“u numpy()”;vs";torch.Tensor();,python,numpy,multidimensional-array,deep-learning,pytorch,Python,Numpy,Multidimensional Array,Deep Learning,Pytorch,我试图深入了解PyTorch张量记忆模型的工作原理 # input numpy array In [91]: arr = np.arange(10, dtype=float32).reshape(5, 2) # input tensors in two different ways In [92]: t1, t2 = torch.Tensor(arr), torch.from_numpy(arr) # their types In [93]: type(arr), type(t1), typ

我试图深入了解PyTorch张量记忆模型的工作原理

# input numpy array
In [91]: arr = np.arange(10, dtype=float32).reshape(5, 2)

# input tensors in two different ways
In [92]: t1, t2 = torch.Tensor(arr), torch.from_numpy(arr)

# their types
In [93]: type(arr), type(t1), type(t2)
Out[93]: (numpy.ndarray, torch.FloatTensor, torch.FloatTensor)

# ndarray 
In [94]: arr
Out[94]: 
array([[ 0.,  1.],
       [ 2.,  3.],
       [ 4.,  5.],
       [ 6.,  7.],
       [ 8.,  9.]], dtype=float32)

我知道PyTorch张量共享NumPy Ndarray的内存缓冲区。因此,改变一个将反映在另一个。所以,这里我正在切片和更新张量中的一些值
t2

In [98]: t2[:, 1] = 23.0
正如所料,它在
t2
arr
中更新,因为它们共享相同的内存缓冲区

In [99]: t2
Out[99]: 

  0  23
  2  23
  4  23
  6  23
  8  23
[torch.FloatTensor of size 5x2]


In [101]: arr
Out[101]: 
array([[  0.,  23.],
       [  2.,  23.],
       [  4.,  23.],
       [  6.,  23.],
       [  8.,  23.]], dtype=float32)
但是,
t1
也会更新。请记住,
t1
是使用
torch.Tensor()
构建的,而
t2
是使用
torch.from\u numpy()构建的

因此,无论我们是使用还是从数据数组构造张量,所有这些张量和数据数组共享相同的内存缓冲区

In [99]: t2
Out[99]: 

  0  23
  2  23
  4  23
  6  23
  8  23
[torch.FloatTensor of size 5x2]


In [101]: arr
Out[101]: 
array([[  0.,  23.],
       [  2.,  23.],
       [  4.,  23.],
       [  6.,  23.],
       [  8.,  23.]], dtype=float32)
基于这一理解,我的问题是,为什么只有一个专门的功能才能完成这项工作


我看了PyTorch文档,但它没有提到这方面的任何内容?有什么想法/建议吗?

这来自
\u torch\u docs.py
;还有可能讨论“为什么”

摘自
numpy
文档:

不同的
ndarray
可以共享相同的数据,因此在一个ndarray中所做的更改可能在另一个ndarray中可见。也就是说,一个
ndarray
可以是另一个
ndarray
的“视图”,它所引用的数据由“基本”
ndarray
处理

Pytorch
文档

如果给定了
numpy.ndarray
torch.Tensor
、或
torch.Storage
,则返回共享相同数据的新张量。如果给定一个Python序列,将从该序列的副本创建一个新的张量

from_numpy()
自动继承输入数组
dtype
。另一方面,
torch.Tensor
torch.FloatTensor
的别名

因此,如果将
int64
数组传递给
torch.Tensor
,则输出张量为float张量,它们不会共享存储
torch.from_numpy
按预期为您提供
torch.LongTensor

a = np.arange(10)
ft = torch.Tensor(a)  # same as torch.FloatTensor
it = torch.from_numpy(a)

a.dtype  # == dtype('int64')
ft.dtype  # == torch.float32
it.dtype  # == torch.int64

建议在Pytorch中构建张量的方法是使用以下两个工厂函数:
torch.tensor
torch.as\tensor

torch.tensor
始终复制数据。例如,
torch.tensor(x)
相当于
x.clone().detach()


torch.as_tensor
总是试图避免数据的拷贝。
as_tensor
避免复制数据的一种情况是,原始数据是一个numpy数组

我试着按照你说的去做,结果一切正常: Torch 1.8.1、Numpy 1.20.1、python 3.8.5

x = np.arange(8, dtype=np.float64).reshape(2,4)
y_4mNp = torch.from_numpy(x)
y_t = torch.tensor(x)
print(f"x={x}\ny_4mNp={y_4mNp}\ny_t={y_t}") 
所有变量现在的值与预期值相同:

x=[[0. 1. 2. 3.]
 [4. 5. 6. 7.]]
y_4mNp=tensor([[0., 1., 2., 3.],
        [4., 5., 6., 7.]], dtype=torch.float64)
y_t=tensor([[0., 1., 2., 3.],
        [4., 5., 6., 7.]], dtype=torch.float64)
From_numpy使用的底层内存与np变量使用的内存相同。 因此,改变np或.from_numpy变量会相互影响,但不会影响张量变量。 但是对y\u t的更改只影响它本身,而不影响numpy或from\u numpy变量

x[0,1] = 111       ## changed the numpy variable itself directly
y_4mNp[1,:] = 500  ## changed the .from_numpy variable
y_t[0,:] = 999     ## changed the tensor variable
print(f"x={x}\ny_4mNp={y_4mNp}\ny_t={y_t}")
现在输出:

x=[[  0. 111.   2.   3.]
 [500. 500. 500. 500.]]
y_4mNp=tensor([[  0., 111.,   2.,   3.],
        [500., 500., 500., 500.]], dtype=torch.float64)
y_t=tensor([[999., 999., 999., 999.],
        [  4.,   5.,   6.,   7.]], dtype=torch.float64)

不知道这是否是早期版本的问题?

非常有趣的问题。我不知道答案,但我怀疑
torch.Tensor()
可能接受其他形式的输入(例如,列表),但
torch.from_numpy()
仅在numpy数组上运行。此评论是关于
torch.Tensor
torch.as_Tensor
,这是很好的了解。但它并没有解决OP关于火炬的问题。
x=[[  0. 111.   2.   3.]
 [500. 500. 500. 500.]]
y_4mNp=tensor([[  0., 111.,   2.,   3.],
        [500., 500., 500., 500.]], dtype=torch.float64)
y_t=tensor([[999., 999., 999., 999.],
        [  4.,   5.,   6.,   7.]], dtype=torch.float64)