Pytorch 的“折叠”和“展开”是如何工作的?

Posted

技术标签:

【中文标题】Pytorch 的“折叠”和“展开”是如何工作的?【英文标题】:How does Pytorch's "Fold" and "Unfold" work? 【发布时间】:2019-05-27 02:00:19 【问题描述】:

我已经通过了official doc。我很难理解这个函数的用途以及它是如何工作的。有人可以用外行的方式解释吗?

尽管我使用的 Pytorch 版本与文档匹配,但他们提供的示例出现错误。也许修复我所做的错误应该教会我一些东西?文档中给出的sn-p是:

   fold = nn.Fold(output_size=(4, 5), kernel_size=(2, 2))
   input = torch.randn(1, 3 * 2 * 2, 1)
   output = fold(input)
   output.size()

而固定的sn-p是:

   fold = nn.Fold(output_size=(4, 5), kernel_size=(2, 2))
   input = torch.randn(1, 3 * 2 * 2, 3 * 2 * 2)
   output = fold(input)
   output.size()

谢谢!

【问题讨论】:

【参考方案1】:

unfoldfold 用于促进“滑动窗口”操作(如卷积)。 假设您想将函数 foo 应用于特征图/图像中的每个 5x5 窗口:

from torch.nn import functional as f
windows = f.unfold(x, kernel_size=5)

现在windowssize的batch-(5*5*x.size(1))-num_windows,你可以在windows上申请foo

processed = foo(windows)

现在你需要将processed“折叠”回x的原始大小:

out = f.fold(processed, x.shape[-2:], kernel_size=5)

您需要注意paddingkernel_size,这可能会影响您将processed“折叠”回x 大小的能力。 此外,fold sums 覆盖重叠的元素,因此您可能希望将 fold 的输出除以补丁大小。

【讨论】:

【参考方案2】:

一维展开很容易:

x = torch.arange(1, 9).float()
print(x)
# dimension, size, step
print(x.unfold(0, 2, 1))
print(x.unfold(0, 3, 2))

输出:

tensor([1., 2., 3., 4., 5., 6., 7., 8.])
tensor([[1., 2.],
        [2., 3.],
        [3., 4.],
        [4., 5.],
        [5., 6.],
        [6., 7.],
        [7., 8.]])
tensor([[1., 2., 3.],
        [3., 4., 5.],
        [5., 6., 7.]])

二维展开(也称为修补

import torch
patch=(3,3)
x=torch.arange(16).float()
print(x, x.shape)
x2d = x.reshape(1,1,4,4)
print(x2d, x2d.shape)
h,w = patch
c=x2d.size(1)
print(c) # channels
# unfold(dimension, size, step)
r = x2d.unfold(2,h,1).unfold(3,w,1).transpose(1,3).reshape(-1, c, h, w)
print(r.shape)
print(r) # result
tensor([ 0.,  1.,  2.,  3.,  4.,  5.,  6.,  7.,  8.,  9., 10., 11., 12., 13.,
        14., 15.]) torch.Size([16])
tensor([[[[ 0.,  1.,  2.,  3.],
          [ 4.,  5.,  6.,  7.],
          [ 8.,  9., 10., 11.],
          [12., 13., 14., 15.]]]]) torch.Size([1, 1, 4, 4])
1
torch.Size([4, 1, 3, 3])

tensor([[[[ 0.,  1.,  2.],
          [ 4.,  5.,  6.],
          [ 8.,  9., 10.]]],


        [[[ 4.,  5.,  6.],
          [ 8.,  9., 10.],
          [12., 13., 14.]]],


        [[[ 1.,  2.,  3.],
          [ 5.,  6.,  7.],
          [ 9., 10., 11.]]],


        [[[ 5.,  6.,  7.],
          [ 9., 10., 11.],
          [13., 14., 15.]]]])

【讨论】:

能不能加上对应的.fold操作返回到原来的张量? 查看fold example 通过F.unfold(input=x2d, kernel_size=(3, 3), dilation=(1, 1), stride=(1, 1), padding=(0, 0) 之类的操作,通过单个F.unfold() 调用是否可以获得相同的结果?【参考方案3】:

unfold 将张量想象为更长的张量,其中重复的列/行值“折叠”在彼此之上,然后“展开”:

size 确定折叠的大小 step 确定折叠的频率

例如对于 2x5 张量,使用 step=1 展开它,并在 dim=1 上修补 size=2

x = torch.tensor([[1,2,3,4,5],
                  [6,7,8,9,10]])
>>> x.unfold(1,2,1)
tensor([[[ 1,  2], [ 2,  3], [ 3,  4], [ 4,  5]],
        [[ 6,  7], [ 7,  8], [ 8,  9], [ 9, 10]]])

fold 与此操作大致相反,但输出中会汇总“重叠”值。

【讨论】:

你的画为我赚了一分钱!谢谢!

以上是关于Pytorch 的“折叠”和“展开”是如何工作的?的主要内容,如果未能解决你的问题,请参考以下文章

React:如何在内容大小未知时为展开和折叠 Div 设置动画

展开全部/折叠所有不工作的类列表

展开和折叠 tableView Sections

如何在 SwiftUI 中制作“显示”式的折叠/展开动画?

html5 - 如何折叠和展开复杂的表格元素

我们如何快速在表格视图底部添加展开和折叠单元格