使用 grad 将 PyTorch 张量调整为更小的尺寸

Posted

技术标签:

【中文标题】使用 grad 将 PyTorch 张量调整为更小的尺寸【英文标题】:Resizing PyTorch tensor with grad to smaller size 【发布时间】:2020-06-25 02:51:20 【问题描述】:

我正在尝试将张量从 (3,3) 缩小到 (1, 1),但我想保留原始张量:

import torch

a = torch.rand(3, 3)
a_copy = a.clone()
a_copy.resize_(1, 1)

我的初始张量中需要requires_grad=True,但 PyTorch 禁止我尝试调整副本大小:

a = torch.rand(3, 3, requires_grad=True)
a_copy = a.clone()
a_copy.resize_(1, 1)

抛出错误:

Traceback (most recent call last):
  File "pytorch_test.py", line 7, in <module>
    a_copy.resize_(1, 1)
RuntimeError: cannot resize variables that require grad

克隆和分离

我也试过.clone().detach()

a = torch.rand(3, 3, requires_grad=True)
a_copy = a.clone().detach()

with torch.no_grad():
    a_copy.resize_(1, 1)

这会给出这个错误:

Traceback (most recent call last):
  File "pytorch_test.py", line 14, in <module>
    a_copy.resize_(1, 1)
RuntimeError: set_sizes_contiguous is not allowed on a Tensor created from .data or .detach().
If your intent is to change the metadata of a Tensor (such as sizes / strides / storage / storage_offset)
without autograd tracking the change, remove the .data / .detach() call and wrap the change in a `with torch.no_grad():` block.
For example, change:
    x.data.set_(y)
to:
    with torch.no_grad():
        x.set_(y)

the docs 和 #15070 中已说明此行为。

no_grad()

因此,按照他们在错误消息中的说明,我删除了.detach() 并改用no_grad()

a = torch.rand(3, 3, requires_grad=True)
a_copy = a.clone()

with torch.no_grad():
    a_copy.resize_(1, 1)

但它仍然给我一个关于 grad 的错误:

Traceback (most recent call last):
  File "pytorch_test.py", line 21, in <module>
    a_copy.resize_(1, 1)
RuntimeError: cannot resize variables that require grad

类似问题

我查看了Resize PyTorch Tensor,但该示例中的张量保留了所有原始值。 我还查看了Pytorch preferred way to copy a tensor,这是我用来复制张量的方法。

我使用的是 PyTorch 1.4.0 版

【问题讨论】:

您是否尝试过先分离再克隆:a_copy = a.detach().clone() @AndreasK。不...我刚刚尝试过,它有效 【参考方案1】:

有一个narrow()函数:

def samestorage(x,y):
    if x.storage().data_ptr()==y.storage().data_ptr():
        print("same storage")
    else:
        print("different storage")
def contiguous(y):
    if True==y.is_contiguous():
        print("contiguous")
    else:
        print("non contiguous")
# narrow => same storage contiguous tensors
import torch
x = torch.randn(3, 3, requires_grad=True)
y = x.narrow(0, 1, 2) #dim, start, len  
print(x)
print(y)
contiguous(y)
samestorage(x,y)

输出:

tensor([[ 1.1383, -1.2937,  0.8451],
        [ 0.0151,  0.8608,  1.4623],
        [ 0.8490, -0.0870, -0.0254]], requires_grad=True)
tensor([[ 0.0151,  0.8608,  1.4623],
        [ 0.8490, -0.0870, -0.0254]], grad_fn=<SliceBackward>)
contiguous
same storage

【讨论】:

【参考方案2】:

我认为你应该先分离然后克隆:

a = torch.rand(3, 3, requires_grad=True)
a_copy = a.detach().clone()
a_copy.resize_(1, 1)

注意:a.detach() 返回一个与当前图形分离的 new 张量(它不会像 a.detach_() 那样将 a 本身从图形中分离出来)。但是因为它与a 共享存储,所以你也应该克隆它。这样,无论您对a_copy 做什么,都不会影响a。但是我不确定为什么a.detach().clone() 有效,但a.clone().detach() 给出错误。

编辑

以下代码也有效(这可能是更好的解决方案):

a = torch.rand(3, 3, requires_grad=True)

with torch.no_grad():
    a_copy = a.clone()
    a_copy.resize_(1, 1)

【讨论】:

@Moon Cheesez 我已经编辑了答案。你也可以使用with torch.no_grad()

以上是关于使用 grad 将 PyTorch 张量调整为更小的尺寸的主要内容,如果未能解决你的问题,请参考以下文章

pytorch 中张量的 Autograd.grad()

将图像调整为更小只是切断边缘

Pytorch RuntimeError:张量的元素 0 不需要 grad 并且没有 grad_fn

Pytorch (1.0) 中类似外观操作的不同 `grad_fn`

深度之眼PyTorch训练营第二期 ---基础数据结构-张量

当窗口垂直调整为更小的尺寸时,避免 WPF 状态栏完全折叠