Модель памяти Pytorch: как работает «torch.from_ numpy ()»? - PullRequest
3 голосов
/ 30 апреля 2020

Я пытаюсь глубоко понять, как работает torch.from_numpy().

import numpy as np
import torch

arr = np.zeros((3, 3), dtype=np.float32)
t = torch.from_numpy(arr)
print("arr: {0}\nt: {1}\n".format(arr, t))

arr[0,0]=1
print("arr: {0}\nt: {1}\n".format(arr, t))

print("id(arr): {0}\nid(t): {1}".format(id(arr), id(t)))

Вывод выглядит так:

arr: [[0. 0. 0.]
 [0. 0. 0.]
 [0. 0. 0.]]
t: tensor([[0., 0., 0.],
        [0., 0., 0.],
        [0., 0., 0.]])

arr: [[1. 0. 0.]
 [0. 0. 0.]
 [0. 0. 0.]]
t: tensor([[1., 0., 0.],
        [0., 0., 0.],
        [0., 0., 0.]])

id(arr): 2360964353040
id(t): 2360964352984

Это часть do c из torch.from_numpy():

from_ numpy (ndarray) -> Tensor

Создает: class: Tensor из a: class: numpy.ndarray .

Возвращенный тензор и: attr: ndarray совместно используют одну и ту же память . Изменения в тензоре будут отражены в: attr: ndarray и наоборот. Возвращаемый тензор не может быть изменен в размере.

И это взято из do c из id():

Возвращает идентификатор объекта.

Это гарантированно будет уникальным среди одновременно существующих объектов. (CPython использует адрес памяти объекта. )

Итак, возникает вопрос: поскольку ndarray arr и тензор t совместно используют одну и ту же память почему у них разные адреса памяти?

Есть идеи / предложения?

1 Ответ

2 голосов
/ 30 апреля 2020

Да, t и arr - это разные Python объекты в разных областях памяти (следовательно, разные id), но оба указывают на один и тот же адрес памяти, который содержит данные (смежные (обычно) C массив).

numpy работает в этом регионе с использованием кода C, связанного с функциями Python, то же самое относится и к torch (но с использованием C++). id() ничего не знает об адресе памяти самих данных, только об их «обертках».

РЕДАКТИРОВАТЬ: Когда вы назначаете b = a (при условии a равен np.array), оба являются ссылками на одну и ту же оболочку Python (np.ndarray). Другими словами это один и тот же объект с другим именем .

Это просто, как работает назначение Python, см. документацию . Все приведенные ниже случаи также вернут True:

import torch
import numpy as np

tensor = torch.tensor([1,2,3])
tensor2 = tensor
id(tensor) == id(tensor2)

arr = np.array([1, 2, 3, 4, 5])
arr2 = arr
id(arr) == id(arr2)

some_str = "abba"
other_str = some_str
id(some_str) == id(other_str)

value = 0
value2 = value
id(value) == id(value2)

Теперь, когда вы используете torch.from_numpy на np.ndarray, у вас есть два объекта разных классов (torch.Tensor и оригинальный np.ndarray). ). Поскольку они бывают разных типов, они не могут иметь одинаковые id. Можно видеть, что этот случай аналогичен приведенному ниже:

value = 3
string_value = str(3)

id(value) == id(string_value)

Здесь интуитивно понятно, что string_value и value - два разных объекта в разных местах памяти.

РЕДАКТИРОВАНИЕ 2:

Все во всех концепциях Python объекта и базового C массива должны быть разделены. id() не знает о C привязках (как это могло быть?), Но он знает об адресах памяти структур Python (torch.Tensor, np.ndarray).

В случае numpy и torch.tensor возможны следующие ситуации:

  • отдельно на уровне Python, но с использованием той же области памяти для массива (torch.from_numpy)
  • отдельно на уровне Python и в основной области памяти (одна torch.tensor и другая np.array). Может быть создан с помощью from_numpy с последующей clone() или аналогичной операцией глубокого копирования.
  • то же самое на уровне Python и базовой области памяти (например, два объекта torch.tensor, один ссылается на другой, как указано выше) )
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...