F.pad的使用与报错记录
原始文档:https://www.yuque.com/lart/ugkv9f/iftd9v
函数原型
函数文档:https://pytorch.org/docs/1.12/generated/torch.nn.functional.pad.html#torch-nn-functional-pad
torch.nn.functional.pad(input, pad, mode='constant', value=None) → Tensor
Padding格式
- 1D-tensor:
(p_left, p_right)
- 2D-tensor:
(p_left, p_right, p_top, p_bottom)
- 3D-tensor:
(p_left, p_right, p_top, p_bottom, p_front, p_back)
四种模式
这一函数用于实现对高维tensor的形状补齐操作。PyTorch本身提供了四种padding模式:
-
constant
:使用指定的常数value
补齐指定的维度。对于数据012
,使用0补齐,结果可以为0001200
。 -
reflect
:使用tensor自身的值按照“反射”的方式补齐指定的维度。对于数据012
,结果可以为2101210
。 -
replicate
:使用tensor自身边界值补齐指定的维度。对于数据012
,结果可以为0001222
。 -
circular
:使用tensor自身的值按照“循环”的方式补齐指定的维度。对于数据012
,结果可以为1201201
。
需要注意的是,文档强调了这一点:
Constant padding is implemented for arbitrary dimensions.
Replicate and reflection padding are implemented for padding the last 3 dimensions of a 4D or 5D input tensor, the last 2 dimensions of a 3D or 4D input tensor, or the last dimension of a 2D or 3D input tensor.
这四种模式使用输出展示会更便于理解一些,下面是一个例子:
import torch
import torch.nn.functional as F
pad = [2, 2, 2, 2]
x = torch.arange(9, dtype=torch.float32).reshape(1, 1, 3, 3)
print("x")
print(x)
print("F.pad(x, pad=pad, mode='constant', value=0)")
print(F.pad(x, pad=pad, mode='constant', value=0))
print("F.pad(x, pad=pad, mode='replicate')")
print(F.pad(x, pad=pad, mode='replicate'))
print("F.pad(x, pad=pad, mode='reflect')")
print(F.pad(x, pad=pad, mode='reflect'))
print("F.pad(x, pad=pad, mode='circular')")
print(F.pad(x, pad=pad, mode='circular'))
对应的输出为:
x
tensor([[[[0., 1., 2.],
[3., 4., 5.],
[6., 7., 8.]]]])
F.pad(x, pad=pad, mode='constant', value=0)
tensor([[[[0., 0., 0., 0., 0., 0., 0.],
[0., 0., 0., 0., 0., 0., 0.],
[0., 0., 0., 1., 2., 0., 0.],
[0., 0., 3., 4., 5., 0., 0.],
[0., 0., 6., 7., 8., 0., 0.],
[0., 0., 0., 0., 0., 0., 0.],
[0., 0., 0., 0., 0., 0., 0.]]]])
F.pad(x, pad=pad, mode='replicate')
tensor([[[[0., 0., 0., 1., 2., 2., 2.],
[0., 0., 0., 1., 2., 2., 2.],
[0., 0., 0., 1., 2., 2., 2.],
[3., 3., 3., 4., 5., 5., 5.],
[6., 6., 6., 7., 8., 8., 8.],
[6., 6., 6., 7., 8., 8., 8.],
[6., 6., 6., 7., 8., 8., 8.]]]])
F.pad(x, pad=pad, mode='reflect')
tensor([[[[8., 7., 6., 7., 8., 7., 6.],
[5., 4., 3., 4., 5., 4., 3.],
[2., 1., 0., 1., 2., 1., 0.],
[5., 4., 3., 4., 5., 4., 3.],
[8., 7., 6., 7., 8., 7., 6.],
[5., 4., 3., 4., 5., 4., 3.],
[2., 1., 0., 1., 2., 1., 0.]]]])
F.pad(x, pad=pad, mode='circular')
tensor([[[[4., 5., 3., 4., 5., 3., 4.],
[7., 8., 6., 7., 8., 6., 7.],
[1., 2., 0., 1., 2., 0., 1.],
[4., 5., 3., 4., 5., 3., 4.],
[7., 8., 6., 7., 8., 6., 7.],
[1., 2., 0., 1., 2., 0., 1.],
[4., 5., 3., 4., 5., 3., 4.]]]])
可能会遇到的报错
常见的错误主要是因为padding的数量超过了对应模式的要求。
对于constant
和replicate
对于padding并没有限制。
但是另外两种模式replicate
和circular
就有要求了。
RuntimeError: Argument #4: Padding size should be less than the corresponding input dimension, but got: padding (3, 3) at dimension 3 of input 4
这发生在reflect
模式中,padding的数量必须小于对应维度的大小。
import torch
import torch.nn.functional as F
pad = [3, 3, 3, 3]
x = torch.arange(9, dtype=torch.float32).reshape(1, 1, 3, 3)
print("F.pad(x, pad=pad, mode='reflect')")
print(F.pad(x, pad=pad, mode='reflect'))
"""
F.pad(x, pad=pad, mode='reflect')
Traceback (most recent call last):
File "e:/Coding/PythonTools/TorchPadding/main.py", line 20, in <module>
print(F.pad(x, pad=pad, mode='reflect'))
File "D:\Programming\Python\envs\pt1102\lib\site-packages\torch\nn\functional.py", line 4189, in _pad
return torch._C._nn.reflection_pad2d(input, pad)
RuntimeError: Argument #4: Padding size should be less than the corresponding input dimension, but got: padding (3, 3) at
dimension 3 of input 4
"""
这一错误仔细思考一下其实也可以理解,因为对于序列012
,如果在右侧reflect padding 3位,对于前两位可以直观的获得即为10
,但是第三位如何获取就属于未明确定义的问题了。为了解决这个问题,则需要自定义一种规则。
如果我们定义reflect按照三角波的形状周期重复,则扩展后的序列可以设计为:...20121
+012
+101210...
此时我们则可以直接使用多次reflect padding来等价实现:
x = torch.arange(9, dtype=torch.float32).reshape(1, 1, 3, 3)
print("F.pad(x, pad=pad, mode='reflect')")
# this `pad` will raise an error
# pad = [3, 3, 3, 3]
# print("pad=", pad)
# print(F.pad(x, pad=pad, mode='reflect'))
# let's use a indirect method to imitate `pad = [3, 3, 3, 3]`
pad = [2, 2, 2, 2]
x = F.pad(x, pad=pad, mode='reflect')
pad = [1, 1, 1, 1]
x = F.pad(x, pad=pad, mode='reflect')
print(x)
此时输出:
F.pad(x, pad=pad, mode='reflect')
tensor([[[[4., 5., 4., 3., 4., 5., 4., 3., 4.],
[7., 8., 7., 6., 7., 8., 7., 6., 7.],
[4., 5., 4., 3., 4., 5., 4., 3., 4.],
[1., 2., 1., 0., 1., 2., 1., 0., 1.],
[4., 5., 4., 3., 4., 5., 4., 3., 4.],
[7., 8., 7., 6., 7., 8., 7., 6., 7.],
[4., 5., 4., 3., 4., 5., 4., 3., 4.],
[1., 2., 1., 0., 1., 2., 1., 0., 1.],
[4., 5., 4., 3., 4., 5., 4., 3., 4.]]]])
当然还有一个更一般的实现,这里实际上还存在优化的空间,不过作为参考而言已经足够:
import torch
import torch.nn.functional as F
def infinite_reflect_padding(x: torch.Tensor, pad: tuple) -> torch.Tensor:
"""Padding with reflect mode that breaks the limit.
Args:
x (torch.Tensor): Input tensor.
pad (tuple): Padding tuple: left, right, top, bottom
Returns:
torch.Tensor: Padded tensor.
"""
B, C, H, W = x.shape
assert len(pad) == 4
if W == 1:
# must not pad the tensor.
if not (pad[0] == 0 and pad[1] == 0):
raise ValueError(pad)
if H == 1:
# must not pad the tensor.
if not (pad[2] == 0 and pad[3] == 0):
raise ValueError(pad)
base_pad = [W-1, W-1, H-1, H-1]
first_padding = []
other_padding = []
for p, base_p in zip(pad, base_pad):
if p <= base_p:
first_padding.append(p)
other_padding.append([0, 0])
else:
first_padding.append(base_p)
other_padding.append(divmod(p, base_p))
x = F.pad(x, pad=first_padding, mode='reflect')
for i, (quotient, remainder) in enumerate(other_padding):
pad_template = [0, 0, 0, 0]
for _ in range(quotient):
pad_template[i] = base_pad[i]
x = F.pad(x, pad=pad_template, mode='reflect')
pad_template[i] = remainder
x = F.pad(x, pad=pad_template, mode='reflect')
return x
# let's use a indirect method to imitate it
x = torch.arange(12, dtype=torch.float32).reshape(1, 1, 3, 4)
print("F.pad(x, pad=pad, mode='reflect')")
x = infinite_reflect_padding(x, pad=(2, 3, 5, 4))
print(x)
输出:文章来源:https://www.toymoban.com/news/detail-408163.html
F.pad(x, pad=pad, mode='reflect')
tensor([[[[ 6., 5., 4., 5., 6., 7., 6., 5., 4.],
[10., 9., 8., 9., 10., 11., 10., 9., 8.],
[ 6., 5., 4., 5., 6., 7., 6., 5., 4.],
[ 2., 1., 0., 1., 2., 3., 2., 1., 0.],
[ 6., 5., 4., 5., 6., 7., 6., 5., 4.],
[10., 9., 8., 9., 10., 11., 10., 9., 8.],
[ 6., 5., 4., 5., 6., 7., 6., 5., 4.],
[ 2., 1., 0., 1., 2., 3., 2., 1., 0.],
[ 6., 5., 4., 5., 6., 7., 6., 5., 4.],
[10., 9., 8., 9., 10., 11., 10., 9., 8.],
[ 6., 5., 4., 5., 6., 7., 6., 5., 4.],
[ 2., 1., 0., 1., 2., 3., 2., 1., 0.],
[ 6., 5., 4., 5., 6., 7., 6., 5., 4.],
[10., 9., 8., 9., 10., 11., 10., 9., 8.],
[ 6., 5., 4., 5., 6., 7., 6., 5., 4.],
[ 2., 1., 0., 1., 2., 3., 2., 1., 0.]]]])
AssertionError: Padding value causes wrapping around more than once.
这发生在circular
模式中,padding的数量不得超出原始tensor对应维度的大小。文章来源地址https://www.toymoban.com/news/detail-408163.html
import torch
import torch.nn.functional as F
pad = [4, 4, 4, 4]
x = torch.arange(9, dtype=torch.float32).reshape(1, 1, 3, 3)
print("F.pad(x, pad=pad, mode='circular')")
print(F.pad(x, pad=pad, mode='circular'))
"""
F.pad(x, pad=pad, mode='circular')
Traceback (most recent call last):
File "e:/Coding/PythonTools/TorchPadding/main.py", line 17, in <module>
print(F.pad(x, pad=pad, mode='circular'))
File "D:\Programming\Python\envs\pt1102\lib\site-packages\torch\nn\functional.py", line 4193, in _pad
return _pad_circular(input, pad)
File "D:\Programming\Python\envs\pt1102\lib\site-packages\torch\nn\functional.py", line 4585, in _pad_circular
assert padding[-(idx * 2 + 1)] <= size, "Padding value causes wrapping around more than once."
AssertionError: Padding value causes wrapping around more than once.
"""
到了这里,关于PyTorch之F.pad的使用与报错记录的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!