web-dev-qa-db-fra.com

Modèle de mémoire PyTorch: "torch.from_numpy ()" vs "torch.Tensor ()"

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?

15
kmario23

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
5
Viacheslav Kroilov

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'une ndarray peut être une "vue" sur une autre ndarray, 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 ou torch.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.

1
ericdeansanchez

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. 

0
Jadiel de Armas