使用方法:
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]
我们想将这个特征图连续的在分辨率维度(H和W)维度取出特征。就像下面这样:
返回值是一个三维向量;【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(即输出的高),计算公式如下所示:
这里是引用举个栗子:假设输入通道数为3,kernel size为(2,2),图片最常见的通道数为3(所以我们拿来举例),经过Unfolder方法后,输出的高变为3*2*2=12,即输出的H为12。
计算完成之后,我们需要计算w,计算公式如下所示:
其中,d代表的是空间的所有维度数,例如空间维度为(H,W),则d=2。下面通过举例,我们来计算输出的w。
举个栗子:如果输入的H、W分别为5,kernel size为2,则输出的w为
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.将一组滑动局部块组合成一个包含张量的大张量。