如何构建一个自动求导兼容的PyTorch模块,可以对张量(如图像)进行调整大小?

8
我在想是否可以在Pytorch中构建一个图像缩放模块,该模块以3 * H * W的torch.tensor作为输入并返回一个张量作为调整大小后的图像。我知道可以将张量转换为PIL图像并使用torchvision,但我还希望从调整大小后的图像向原始图像反向传播梯度,以下示例会在Windows 10上(在PyTorch 0.4.0中)返回此类错误:
import numpy as np
from torchvision import transforms

t2i = transforms.ToPILImage()
i2t = transforms.ToTensor()

trans = transforms.Compose(
    t2i, transforms.Resize(size=200), i2t]
)

test = np.random.normal(size=[3, 300, 300])
test = torch.tensor(test, requires_grad=True)
resized = trans(test)
resized.backward()

print(test.grad)

Traceback (most recent call last):
  File "D:/Projects/Python/PyTorch/test.py", line 41, in <module>
    main()
  File "D:/Projects/Python/PyTorch/test.py", line 33, in main
    resized = trans(test)
  File "D:\Anaconda3\envs\pytorch\lib\site-packages\torchvision\transforms\transforms.py", line 42, in __call__
    img = t(img)
  File "D:\Anaconda3\envs\pytorch\lib\site-packages\torchvision\transforms\transforms.py", line 103, in __call__
    return F.to_pil_image(pic, self.mode)
  File "D:\Anaconda3\envs\pytorch\lib\site-packages\torchvision\transforms\functional.py", line 102, in to_pil_image
    npimg = np.transpose(pic.numpy(), (1, 2, 0))
RuntimeError: Can't call numpy() on Variable that requires grad. Use var.detach().numpy() instead.

似乎我不能在不先将张量从自动求导中分离出来的情况下进行“imresize”,但是分离它会防止我计算梯度。

是否有一种方法可以构建一个torch函数/模块,它与自动求导兼容,并且执行与torchvision.transforms.Resize相同的操作?非常感谢您的帮助!


2
双线性调整大小只是周围像素值的线性组合,而且这个操作在数学上是可微的,所以毫无道理为什么PyTorch不能反向传播其梯度... - Lotayou
你可能正在考虑卷积层?一个方便的例子是 https://github.com/yunjey/pytorch-tutorial/blob/master/tutorials/02-intermediate/convolutional_neural_network/main.py - xxbidiao
我觉得你的问题与空间变换网络非常相似,它们也学习仿射变换参数。https://arxiv.org/pdf/1506.02025.pdf - macharya
自动求导仅适用于PyTorch操作,它并非魔法。在幕后,它为每个函数调用backward()函数,因此它无法处理像PIL的resize这样的非PyTorch函数。 - Separius
这个回答是否解决了你的问题?[如何调整 PyTorch 张量的大小?] (https://dev59.com/XVMH5IYBdhLWcg3wsBUS) - iacob
2个回答

3

1
注意:这已经被torch.nn.functional.interpolate()所取代。 - iacob

-1

我刚刚想到了如何在实现自定义损失函数时保留梯度。

诀窍是将你的结果附加到虚拟梯度上。

def custom_loss(tensor1, tensor2):
    # convert tensors to PIL image, doing calculation, we have output = 0.123
    grad = (tensor1 + tensor2).sum()
    loss = grad - grad + output
    return loss

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接