J'essaie de comprendre en profondeur le fonctionnement du modèle de mémoire PyTorch Tensor.
# 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)
Je sais que les tenseurs PyTorch partagent la mémoire tampon de NumPy ndarrays. Ainsi, changer l'un se reflétera dans l'autre. Donc, ici, je coupe et met à jour des valeurs dans le Tensor t2
In [98]: t2[:, 1] = 23.0
Et comme prévu, il est mis à jour dans t2
et arr
car ils partagent le même tampon de mémoire.
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)
Mais, t1
est également mis à jour. Rappelez-vous que t1
a été construit en utilisant torch.Tensor()
alors que t2
a été construit en utilisant torch.from_numpy()
In [100]: t1
Out[100]:
0 23
2 23
4 23
6 23
8 23
[torch.FloatTensor of size 5x2]
Ainsi, que nous utilisions torch.from_numpy()
ou torch.Tensor()
pour construire un tenseur à partir d’un ndarray, tous de tels tenseurs et ndarrays partagent le même tampon de mémoire.
Sur la base de cette compréhension, ma question est la suivante: pourquoi une fonction dédiée torch.from_numpy()
existe-t-elle alors que/ torch.Tensor()
peut faire le travail?
J'ai regardé la documentation de PyTorch mais cela ne mentionne rien à ce sujet? Des idées/suggestions?
from_numpy()
hérite automatiquement du tableau d'entrée dtype
. torch.Tensor
est un alias pour torch.FloatTensor
.
Par conséquent, si vous passez int64
array à torch.Tensor
, le tenseur de sortie est un tenseur à virgule flottante et le stockage ne sera pas partagé. torch.from_numpy
vous donne torch.LongTensor
comme prévu.
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
Cela vient de _torch_docs.py
; il y a aussi une discussion possible sur le "why" here .
def from_numpy(ndarray): # real signature unknown; restored from __doc__
"""
from_numpy(ndarray) -> Tensor
Creates a :class:`Tensor` from a :class:`numpy.ndarray`.
The returned tensor and `ndarray` share the same memory.
Modifications to the tensor will be reflected in the `ndarray`
and vice versa. The returned tensor is not resizable.
Example::
>>> a = numpy.array([1, 2, 3])
>>> t = torch.from_numpy(a)
>>> t
torch.LongTensor([1, 2, 3])
>>> t[0] = -1
>>> a
array([-1, 2, 3])
"""
pass
Tiré de la numpy
docs:
Différents
ndarrays
peuvent partager les mêmes données, de sorte que les modifications apportées dans un ndarray peuvent être visibles dans un autre. C'est-à-dire qu'unendarray
peut être une "vue" sur une autrendarray
, et les données auxquelles elle fait référence sont gérées par la "base"ndarray
.
Pytorch docs
:
Si un
numpy.ndarray
,torch.Tensor
outorch.Storage
est donné, un nouveau tenseur partageant les mêmes données est renvoyé. Si une séquence Python est donnée, un nouveau tenseur est créé à partir d'une copie de la séquence.
La méthode recommandée pour construire des tenseurs dans Pytorch consiste à utiliser les deux fonctions d'usine suivantes: torch.tensor
et torch.as_tensor
.
torch.tensor
always copie les données. Par exemple, torch.tensor(x)
est équivalent à x.clone().detach()
.
torch.as_tensor
essaie toujours pour éviter les copies des données. L'un des cas où as_tensor
évite de copier les données est si les données d'origine sont un tableau numpy.