展开¶
- class torch.nn.Unfold(kernel_size, dilation=1, padding=0, stride=1)[源代码]¶
从批量输入张量中提取滑动局部块。
考虑一个形状为 的批处理
input
张量, 其中 是批次维度, 是通道维度, 而 表示任意空间维度。此操作将input
的空间维度内的每个滑动kernel_size
大小的块展平为 一个3维output
张量的列(即最后一维),形状为 ,其中 是每个块内的值总数 (一个块有 个空间 位置,每个位置包含一个 通道向量),而 是 此类块的总数:其中 由
input
的空间维度形成( 以上),并且 遍及所有空间维度。因此,在最后一个维度(列维度)对
output
进行索引,可以得到某个块内的所有值。参数
padding
、stride
和dilation
指定了如何获取滑动块。stride
控制滑动块的步幅。padding
控制重塑之前在每个维度的两侧添加的隐式零填充的数量。dilation
控制卷积核点之间的间距;也称为à trous算法。 这很难描述,但这个 链接 有一个很好的可视化展示了dilation
的作用。
- Parameters
如果
kernel_size
、dilation
、padding
或stride
是整数或长度为1的元组,它们的值将在所有空间维度上复制。对于两个输入空间维度的情况,这种操作有时被称为
im2col
。
注意
Fold
通过将所有包含块中的所有值相加来计算结果中大张量中的每个组合值。Unfold
通过从大张量中复制来提取局部块中的值。因此,如果块重叠,它们不是彼此的逆。一般来说,折叠和展开操作的关系如下。考虑使用相同参数创建的
Fold
和Unfold
实例:>>> fold_params = dict(kernel_size=..., dilation=..., padding=..., stride=...) >>> fold = nn.Fold(output_size=..., **fold_params) >>> unfold = nn.Unfold(**fold_params)
然后对于任何(支持的)
输入
张量,以下等式成立:fold(unfold(input)) == divisor * input
其中
divisor
是一个仅依赖于input
的形状和数据类型的张量:>>> input_ones = torch.ones(input.shape, dtype=input.dtype) >>> divisor = fold(unfold(input_ones))
当
divisor
张量不包含零元素时,fold
和unfold
操作是彼此的逆操作(除以常数因子外)。警告
目前,仅支持4维输入张量(批量图像类张量)。
- Shape:
输入:
输出: 如上所述
示例:
>>> unfold = nn.Unfold(kernel_size=(2, 3)) >>> input = torch.randn(2, 5, 3, 4) >>> output = unfold(input) >>> # 每个patch包含30个值(2x3=6个向量,每个向量有5个通道) >>> # 在3x4的输入中总共有4个块(2x3的核) >>> output.size() torch.Size([2, 30, 4]) >>> # 卷积等价于Unfold + 矩阵乘法 + Fold(或视图到输出形状) >>> inp = torch.randn(1, 3, 10, 12) >>> w = torch.randn(2, 3, 4, 5) >>> inp_unf = torch.nn.functional.unfold(inp, (4, 5)) >>> out_unf = inp_unf.transpose(1, 2).matmul(w.view(w.size(0), -1).t()).transpose(1, 2) >>> out = torch.nn.functional.fold(out_unf, (7, 8), (1, 1)) >>> # 或者等价地(并避免复制), >>> # out = out_unf.view(1, 2, 7, 8) >>> (torch.nn.functional.conv2d(inp, w) - out).abs().max() tensor(1.9073e-06)