使用方法:

def unfold(input, kernel_size, dilation=1, padding=0, stride=1):
    """
    input: tensor数据,四维, Batchsize, channel, height, width
    kernel_size: 核大小,决定输出tensor的数目。稍微详细讲
    dilation: 输出形式是否有间隔,稍后详细讲。
    padding:一般是没有用的必要
    stride: 核的滑动步长。稍后详细讲
"""

假设我们现在有一个张量特征图,其size为[ 1, C, H, W]

python 滑动窗口算法理解 pytorch滑动窗口_python 滑动窗口算法理解

我们想将这个特征图连续的在分辨率维度(H和W)维度取出特征。就像下面这样:

python 滑动窗口算法理解 pytorch滑动窗口_数据_02

返回值是一个三维向量;【B,  C* kH * kW,  L】,
第一项为batchsize,
第二项为 “ kernel-size*kernel-size*C ” 即上图右方的一个立方体的 长*宽*高
第三项为总共有多少个这样的小立方体

就是想把输入tensor数据,按照一定的区域(由核的长宽),不断沿着通道维度取出来,由步长指定核滑动的步长,由dilation指定核内区域哪些被跳过。

这里要说明一下,unfold函数的输入数据是四维,但输出是三维的。假设输入数据是[B, C, H, W], 那么输出数据是 [B,  C* kH * kW,  L], 其中kH是核的高,kW是核宽。 L则是这个高kH宽kW的核能在H*W区域按照指定stride滑动的次数。

上面公式中第一项是指核高kH的情况下,能在高H的特征图上滑动的次数,后一项则是在宽这个维度上。当然默认stride=1

 

具体如何计算输出的size

import torch
import torch.nn as nn
if __name__ == '__main__':
    x = torch.randn(2, 3, 5, 5)
    print(x)
    unfold = nn.Unfold(2)
    y = unfold(x)
    print(y.size())
    print(y)

运行结果:

torch.Size([2, 12, 16])

接下来,我们一步一步分析这个结果是怎么计算出来的?

首先,要知道的是,我们的输入必须是4维的,即(B,C,H,W),其中,B表示Batch size;C代表通道数;H代表feature map的高;W表示feature map的宽。首先,我们假设经过Unfolder处理之后的size为(B,h,w)。然后我们需要计算h(即输出的高),计算公式如下所示:

python 滑动窗口算法理解 pytorch滑动窗口_人工智能_03

这里是引用举个栗子:假设输入通道数为3,kernel size为(2,2),图片最常见的通道数为3(所以我们拿来举例),经过Unfolder方法后,输出的高变为3*2*2=12,即输出的H为12。

计算完成之后,我们需要计算w,计算公式如下所示:

python 滑动窗口算法理解 pytorch滑动窗口_pytorch_04

其中,d代表的是空间的所有维度数,例如空间维度为(H,W),则d=2。下面通过举例,我们来计算输出的w。

举个栗子:如果输入的H、W分别为5,kernel size为2,则输出的w为

python 滑动窗口算法理解 pytorch滑动窗口_人工智能_05


4*4=16,故最终的输出size为[2,12,16]。

fold()

torch.nn.Fold的操作与Unfold相反,将提取出的滑动局部区域块还原成batch的张量形式

Combines an array of sliding local blocks into a large containing tensor.将一组滑动局部块组合成一个包含张量的大张量。