web-dev-qa-db-ja.com

PyTorchメモリモデル: "torch.from_numpy()" vs "torch.Tensor()"

私は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)
_

PyTorchテンソルはNumPy ndarraysのメモリバッファを共有することを知っています。したがって、一方を変更すると他方に反映されます。だから、ここで私はTensor _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_numpy()を使用して構築されたことを思い出してください

_In [100]: t1
Out[100]: 

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

したがって、 torch.from_numpy() または torch.Tensor() を使用してndarrayからテンソルを構築しても、allそのようなテンソルとndarrayは同じメモリバッファを共有します。

この理解に基づいて、私の質問は、単に torch.from_numpy() ができるのに、なぜ専用の関数 torch.Tensor() が存在するのかということです。

PyTorchのドキュメントを見ましたが、これについては何も言及されていませんか?アイデア/提案はありますか?

22
kmario23

from_numpy()は、入力配列dtypeを自動的に継承します。一方、torch.Tensortorch.FloatTensorのエイリアスです。

したがって、int64配列をtorch.Tensorに渡すと、出力テンソルは浮動小数点テンソルになり、ストレージを共有しません。 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
12

これは_torch_docs.py;また、「whyhere に関する議論もあります。

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

numpyドキュメントから取得:

異なるndarraysは同じデータを共有できるため、1つのndarrayで行われた変更が別のndarrayで見えるようになります。つまり、ndarrayは別のndarrayの「ビュー」になることができ、それが参照しているデータは「ベース」ndarrayによって処理されます。

Pytorch docs

もし numpy.ndarraytorch.Tensor、 または torch.Storageが指定された場合、同じデータを共有する新しいテンソルが返されます。 Pythonシーケンスが指定された場合、シーケンスのコピーから新しいテンソルが作成されます。

1
eric

Pytorchでテンソルを構築する推奨方法は、次の2つのファクトリ関数を使用することです:_torch.tensor_および_torch.as_tensor_。

_torch.tensor_ alwaysはデータをコピーします。たとえば、torch.tensor(x)x.clone().detach()と同等です。

_torch.as_tensor_ 常に試行データのコピーを回避します。 _as_tensor_がデータのコピーを回避するケースの1つは、元のデータがnumpy配列である場合です。

1
Jadiel de Armas