问题描述
测试自家编译器的时候遇到了一个问题,同 github issue:Bug in max_pool2d with ceil_mode under certain conditions · Issue #45357 · pytorch/pytorch · GitHub
torch version: 1.5.0+cpu
问题分析
step1:理解官方定义的output shape 计算公式
1. 官方文档
MaxPool2d — PyTorch 1.9.1 documentation
2. v1.5.0+cpu API关键信息
ceil_mode – when True, will use ceil instead of floor to compute the output shape
2. 理解公式
(1)K' = dilation[i] * (kernel_size[i] -1) + 1, 表示膨胀后的滑窗大小
(2)pad_H = Hin + 2 * padding[0]
上述公式简化成:out_H = ceil ( ( pad_H - K') / stride_h + 1)
此公式默认最后至少存在一个滑窗,且滑窗的start在最后一个滑窗范围内,此公式会忽略一种情况(滑窗索引越界),图示如下:
(3)测试问题1:滑窗索引越界问题
同 https://github.com/pytorch/pytorch/issues/45357#, 此issue在较新版本中已解决。
(4)测试问题2:run torch的output shape 与计算公式得到的结果不同
原因:v1.5.0+cpu API描述中没有下面的note,而pytorch实际按照下面的note计算的,即:如果滑窗的start在左边/上边padding 区域,或者input tensor区域,则允许其越界;若滑窗的start在右边/下边padding区域,则忽略此滑窗。
因此pytorch实际outshape计算方式如下:
查看pytorch最新版本的API描述,已经添加此note。
step2:批量case验证v1.5.0+cpu版的错误情形
已知pytorch v1.5.0+cpu版本文档描述不全,因此outshape计算公式按照v1.9.1的来计算:
每行依次是:1.5.0-pytorch运行结果, 计算公式得到的HW,比对结果,
kernel_size, strides, padding, dilations, ceil_mode, input_size, (最后两项可忽略)
批量数据验证:
pytorch v1.5.0存在BUG:滑窗索引越界问题
在pytorch v1.9.2验证错误case,均正确,下面是部分数据。
# case = ([1, 1, 4], [1, 1], [15, 15], [0, 0], [8, 8], True) # pytorch res shape: torch.Size([1, 1, 1]), 版本已修改 # case = ([1, 1, 13], [12, 2], [15, 15], [6, 0], [2, 2], True) # pytorch res shape: torch.Size([1, 1, 1]), 版本已修改 # case = ([1, 132, 5], [1, 1], [15, 15], [0, 0], [15, 15], True) # pytorch res shape: torch.Size([1, 9, 1]), 版本已修改 # case = ([1, 188, 4], [1, 1], [15, 15], [0, 0], [15, 15], True) # pytorch res shape: torch.Size([1, 13, 1]), 版本已修改 case = ([1, 134, 13], [1, 1], [13, 13], [0, 0], [7, 7], True) # pytorch res shape: torch.Size([1, 11, 1]), 版本已修改
最后,介于Pytorch v1.5.0 MaxPool2d本身存在BUG,建议尽量使用最新版本。