Модель памяти 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, все такие тензоры и ndarrays используют один и тот же буфер памяти.
Основываясь на этом понимании, мой вопрос заключается в том, почему функция torch.from_numpy()
существует, когда просто torch.Tensor()
может выполнять задание?
Я посмотрел документацию PyTorch, но в этом ничего не говорится? Любые идеи/предложения?
Ответы
Ответ 1
from_numpy()
автоматически наследует входной массив dtype
. С другой стороны, torch.Tensor
является псевдонимом для torch.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
Ответ 2
Это происходит от _torch_docs.py
; есть также возможная дискуссия о "почему" здесь.
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
docs:
Различные ndarrays
могут совместно использовать одни и те же данные, так что изменения, сделанные в одном ndarray, могут быть видны в другом. То есть, ndarray
может быть "представлением" для другого ndarray
, и данные, на которые он ссылается, заботятся о "базовом" ndarray
.
docs
Pytorch:
Если numpy.ndarray
, torch.Tensor
или torch.Tensor
, torch.Storage
новый тензор, который использует одни и те же данные. Если задана последовательность Python, то создается новый тензор из копии последовательности.
Ответ 3
Рекомендуемый способ построения тензоров в Pytorch - использовать следующие две фабричные функции: torch.tensor
и torch.as_tensor
.
torch.tensor
всегда копирует данные. Например, torch.tensor(x)
эквивалентен x.clone().detach()
.
torch.as_tensor
всегда старается избегать копий данных. Один из случаев, когда as_tensor
избегает копирования данных, - это если исходные данные являются массивом.