详解pytorch fold和unfold用法

先上结论,conv = unfold + matmul + fold. 即卷积操作等价于,先unfold(展开),再执行矩阵乘法matmul,然后再fold(折叠)。具体过程如下:

unfold函数将一个输入Tensor(N,C,H,W) 展开成 (N,C * K1 * K2, Blocks),其中kernel形状为(K1,K2),总的Block数为Blocks。即把输入的Tensor根据kernel的大小展开成Blocks个向量。Block的计算公式如下:
B l o c k s = H b l o c k s × W b l o c k s Blocks = \text H_{blocks} \times W_{blocks} Blocks=Hblocks×Wblocks
其中:
H b l o c k s = H + 2 ∗ p a d d i n g [ 0 ] − k e r n e l [ 0 ] s t r i d e [ 0 ] + 1 H_{blocks} = \frac {H+2*padding[0]-kernel[0]}{stride[0]}+1 Hblocks=stride[0]H+2padding[0]kernel[0]+1

W b l o c k s = W + 2 ∗ p a d d i n g [ 1 ] − k e r n e l [ 1 ] s t r i d e [ 1 ] + 1 W_{blocks} = \frac {W+2*padding[1]-kernel[1]}{stride[1]}+1 Wblocks=stride[1]W+2padding[1]kernel[1]+1

代码举例:

inp = torch.randn(1, 3, 10, 12)
w = torch.randn(2, 3, 4, 5)
inp_unf = torch.nn.functional.unfold(inp, (4, 5))#shape of inp_unf is (1,3*4*5,7*8)

其中,inp_unf的shape计算过程如下
H b l o c k s = 10 − 4 1 + 1 = 7 H_{blocks} = \frac {10-4}{1}+1 = 7 Hblocks=1104+1=7

W b l o c k s = 12 − 5 1 + 1 = 8 W_{blocks} = \frac {12-5}{1}+1 = 8 Wblocks=1125+1=8

out_unf = inp_unf.transpose(1, 2).matmul(w.view(w.size(0), -1).t()).transpose(1, 2)
#shape of out_unf is (1,2,56)

以上代码相当于 inp_unf(1, 60, 56) .t() * w(2 , 3 * 4 * 5).t() → out_unf (1, 56, 2 ) → out_unf (1, 2, 56)

unfold + matmul已经完成,最后是 fold过程. fold过程其实就是unfold的反过程,即把向量折叠回矩阵形式。

out = torch.nn.functional.fold(out_unf, (7, 8), (1, 1))
#out.size() = (1,2,7,8)

以上过程其实等价于直接进行Conv,因此

(torch.nn.functional.conv2d(inp, w) - out).abs().max()
#tensor(1.9073e-06)

可以看出卷积的结果和经过了unfold + matmul + fold的结果差距为10的-6次方,几乎可以认为是相等的了。

总结

利用pytorch 中fold 和unfold的组合可以实现类似Conv操作的滑动窗口,其中如果同一个图片的每个block的参数都是相同的,那么称为参数共享,就是标准的卷积层;如果每个block的参数都不一样,那么就不是参数共享的,此时一般称为局部连接层(Local connected layer)。

参考

https://pytorch.org/docs/stable/generated/torch.nn.Unfold.html

https://pytorch.org/docs/stable/generated/torch.nn.Fold.html

https://blog.csdn.net/LoseInVain/article/details/88139435

  • 5
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
pytorch中的unfold函数是一种图片的分块操作,它可以提取出卷积核滑过的元素,而不进行其他运算。使用unfold函数可以将卷积核滑动扫过的数据提取出来。通过给定的kernel_size和stride参数,unfold函数可以将输入的图片分割成多个块,并按照指定的顺序排列这些块中的像素值。在使用unfold函数之后,可以通过transpose函数对结果进行维度重排,以得到期望的输出形状。通过这种方式,可以方便地对图像进行分块处理,并用于后续的操作,如卷积运算或像ViT模型中的patch embedding操作。 在ViT模型中,patch embedding操作可以将图像的每个分块转换为一个嵌入向量。类似于使用unfold函数将图像分割成多个块,然后将每个块中的像素值转换为嵌入向量。这样就可以将图像中的像素信息转换为嵌入表示,用于后续的视觉任务。通过定义一个可学习的权重参数,可以自定义嵌入向量的维度和形状。使用unfold函数可以方便地实现这一操作,将图像分块并将像素值转换为嵌入向量。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [[pytorch]unfold操作](https://blog.csdn.net/qq_41319370/article/details/125193360)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

daimashiren

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值