pytorch和tensorflow所含的maxpool,虽然名字相同,但是功能是不一样。之前在用pytorch复现darknet里面的yolo-v2时才发现这个问题。在yolov2的第六个maxpool的时候,kernel为2,stride为1,所以
按道理来说呢,输出的边size应该比输入的边size少1,但是yolo的设计是输入和输出的shape要相同。所以才发现了这个问题。
不同之处在于padding的补全方式
pytorch里的maxpool,padding的方式是四周都补0,如果padding等于x,那么输入的feature map就会比原来大上x圈。并且还支持dilation模式Σ( ° △ °|||)︴
而tensorflow里的maxpool,padding方式是分为SAME
和VALID
,在SAME
模式下,padding有时候只会在图像右侧和下方补0,而左侧和上方并不会。不支持dilation。
举个例子
如果输入一个3X3的图片,
1,2,3
4,5,6
7,8,9
对其做kernel_size=2,stride=1的maxpool,那么本应该得到
5,6
8,9
# pytorch版本
import torch
import torch.nn.functional as F
from torch.autograd import Variable
data = torch.FloatTensor([[[[1, 2, 3], [4, 5, 6], [7, 8, 9]]]])
i = Variable(data, requires_grad=True)
res = F.max_pool2d(i, kernel_size=(2, 2), stride=1)
print(res)
# tensorflow版本
import tensorflow as tf
data = np.array([[[[1], [2], [3]], [[4], [5], [6]], [[7], [8], [9]]]])
i = tf.placeholder(dtype=tf.int32, shape=(1, 3, 3, 1))
net = tf.nn.max_pool(i, ksize=(1, 2, 2, 1), strides=(1, 1, 1, 1), padding='VALID')
sess = tf.Session()
sess.run(tf.global_variables_initializer())
out = sess.run([net, ], {i: data})
print(out)
但是如果我们想要保证feature map在输入前后尺寸不变,tensorflow很好实现,把padding模式改成’SAME’就行,但是pytorch就做不到了(有办法么?)因为pytorch里面如果padding=1,那么输出的feature map的尺寸就是4X4的。
Variable containing:
(0 ,0 ,.,.) =
1 2 3 3
4 5 6 6
7 8 9 9
7 8 9 9
[torch.FloatTensor of size 1x1x4x4]
而tensorflow的输出是
[[[[5 6 6]
[8 9 9]
[8 9 9]]]]
pytorch里有pad()方法,可以控制在feature map的边界加上0。
import torch
import torch.nn.functional as F
from torch.autograd import Variable
#
data = torch.FloatTensor([[[[1, 2, 3], [4, 5, 6], [7, 8, 9]]]])
i = Variable(data, requires_grad=True)
pd = (0, 1, 0, 1)
out = F.pad(i, pd, 'constant', 0)
print(out)
res = F.max_pool2d(out, kernel_size=(2, 2), stride=1, padding=0)
print(res)
输出:
Variable containing:
(0 ,0 ,.,.) =
1 2 3 0
4 5 6 0
7 8 9 0
0 0 0 0
[torch.FloatTensor of size 1x1x4x4]
Variable containing:
(0 ,0 ,.,.) =
5 6 6
8 9 9
8 9 9
[torch.FloatTensor of size 1x1x3x3]