Операции на месте с PyTorch

Мне было интересно, как справиться с операциями на месте в PyTorch. Насколько я помню, использование автограда на месте всегда было проблематичным.

И на самом деле я удивлен, что приведенный ниже код работает, хотя я его не тестировал, я считаю, что этот код вызвал бы ошибку в версии 0.3.1.

В основном я хочу, чтобы сделать определенную позицию тензорного вектора на определенное значение, например:

my_tensor[i] = 42

Рабочий пример кода:

# test parameter a
a = torch.rand((2), requires_grad=True)
print('a ', a)
b = torch.rand(2)

# calculation
c = a + b

# performing in-place operation
c[0] = 0
print('c ', c)
s = torch.sum(c)
print('s ', s)

# calling backward()
s.backward()

# optimizer step
optim = torch.optim.Adam(params=[a], lr=0.5)
optim.step()

# changed parameter a
print('changed a', a)

Выход:

a  tensor([0.2441, 0.2589], requires_grad=True)
c  tensor([0.0000, 1.1511], grad_fn=<CopySlices>)
s  tensor(1.1511, grad_fn=<SumBackward0>)
changed a tensor([ 0.2441, -0.2411], requires_grad=True)

Так очевидно в версии 0.4.1. это работает нормально, без предупреждений или ошибок.

Ссылка на эту статью в документации: автоград-механик

Supporting in-place operations in autograd is a hard matter, and we discourage their use in most cases. Autograd’s aggressive buffer freeing and reuse makes it very efficient and there are very few occasions when in-place operations actually lower memory usage by any significant amount. Unless you’re operating under heavy memory pressure, you might never need to use them.

Но хоть и работает, Использование операций на месте в большинстве случаев не рекомендуется.


Итак, мои вопросы:

  • Как много влияет на производительность при использовании операций на месте?

  • Как мне обойтись с использованием операций на месте в таких случаях, когда я хочу установить для одного элемента тензора определенное значение?

Заранее спасибо!

Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
18
0
5 102
3

Ответы 3

Я не уверен, насколько операция на месте влияет на производительность, но могу ответить на второй вопрос. Вы можете использовать маску вместо операций на месте.

a = torch.rand((2), requires_grad=True)
print('a ', a)
b = torch.rand(2)

# calculation
c = a + b

# performing in-place operation
mask = np.zeros(2)
mask[1] =1
mask = torch.tensor(mask)
c = c*mask
...

Для вашего второго запроса, когда вы выполняете c[i] = i или аналогичные операции, обычно вызывается __setitem__. Чтобы выполнить эту операцию на месте, вы можете попробовать вызвать функцию __setitem__ (если она выполняет операцию c[i] = i.

Возможно, это не прямой ответ на ваш вопрос, а просто для информации.

Операции на месте работают для тензоров нелистовой в вычислительном графе.

Тензоры листьев - это тензоры, которые являются «концами» вычислительного графа. Официально (из is_leaf атрибут здесь),

For Tensors that have requires_grad which is True, they will be leaf Tensors if they were created by the user. This means that they are not the result of an operation and so grad_fn is None.

Пример, который работает без ошибок:

a = torch.tensor([3.,2.,7.], requires_grad=True)
print(a)   # tensor([3., 2., 7.], requires_grad=True)
b = a**2
print(b)   # tensor([ 9.,  4., 49.], grad_fn=<PowBackward0>)
b[1] = 0
print(b)   # tensor([ 9.,  0., 49.], grad_fn=<CopySlices>)
c = torch.sum(2*b)
print(c)   # tensor(116., grad_fn=<SumBackward0>)
c.backward()
print(a.grad)  # tensor([12.,  0., 28.])

С другой стороны, операции на месте не работают для тензоров лист.

Пример, вызывающий ошибку:

a = torch.tensor([3.,2.,7.], requires_grad=True)
print(a) # tensor([3., 2., 7.], requires_grad=True)
a[1] = 0
print(a) # tensor([3., 0., 7.], grad_fn=<CopySlices>)
b = a**2
print(b) # tensor([ 9.,  0., 49.], grad_fn=<PowBackward0>)
c = torch.sum(2*b)
print(c) # tensor(116., grad_fn=<SumBackward0>)
c.backward()  # Error occurs at this line. 

# RuntimeError: leaf variable has been moved into the graph interior

Я полагаю, что операция b[1]=0 в первом примере выше на самом деле не является операцией на месте. Я предполагаю, что он создает новый тензор с операцией CopySlices. «Старый b» перед операцией на месте может храниться внутри (просто его имя перезаписывается «новым b»). Нашел красивую фигурку здесь.

старый b --- (CopySlices) ----> новый b

С другой стороны, тензор a - это листовой тензор. После операции CopySlices a[1]=0 он становится промежуточным тензором. Чтобы избежать такой сложной смеси между листовыми тензорами и промежуточными тензорами при обратном распространении, операции CopySlices над листовыми тензорами запрещено сосуществовать с обратным.

Это всего лишь мое личное мнение, поэтому обращайтесь к официальным документам.

Примечание:

Хотя операции на месте работают для промежуточных тензоров, будет безопасно использовать как можно больше клонирования и отсоединения, когда вы выполняете некоторые операции на месте, чтобы явно создать новый тензор, который не зависит от вычислительного графа.

Другие вопросы по теме