6.6.2 最大池化层和平均池化层¶

1. 边缘检测¶

In [ ]:
import sys
sys.path.append(r'D:\WorkSpace\DeepLearning\WebsiteV2')   # 定义自定义模块保存位置
from codes.paddle import common
import paddle
import cv2
import matplotlib.pyplot as plt
image = cv2.imread('../../Images/Materials/chapter06ConvolutionalNetwork/chapter06040EdgeDetectionExample.png', 0)
img = paddle.to_tensor(image, dtype='float32')

# 3×3的垂直边缘检测器
W1 = paddle.to_tensor([[1,-1], [1,-1]])
out_hand_crafted = common.cross_correlation(img, W1)
In [33]:
plt.figure(figsize=(12,6))
ax = plt.subplot(1,2,1)
plt.imshow(cv2.cvtColor(image, cv2.COLOR_BGR2RGB))
ax.set_title('Original Image', fontsize=18)
ax = plt.subplot(1,2,2)
plt.imshow(out_hand_crafted, cmap=plt.cm.binary)
ax.set_title('The Hand-crafted Kernel', fontsize=18)
Out[33]:
Text(0.5, 1.0, 'The Hand-crafted Kernel')

2. 最大池化和平均池化¶

2.0 导入必备库和自定义库¶

In [1]:
import numpy as np
import sys
import paddle
sys.path.append(r'D:\WorkSpace\DeepLearning\WebsiteV2')   # 定义自定义模块保存位置
from codes.paddle import common
In [35]:
#@save common.pool2D
def pool2D(X, pool_size, mode='max'):
    """在池化窗口内进行池化/汇聚运算"""
    "X: 输入矩阵"
    "pool_size:池化窗口的尺度,形态为 [height, width]"
    "mode:max最大池化,avg均值池化"
    h, w = pool_size
    Y = np.zeros((X.shape[0] - h + 1, X.shape[1] - w + 1))
    for i in range(Y.shape[0]):
        for j in range(Y.shape[1]):
            if mode == 'max':
                Y[i,j] = X[i:i+h, j:j+w].max()
            elif mode == 'avg':
                Y[i,j] = X[i:i+h, j:j+w].mean()
    return Y

2.1 生成6×6的卷积层条纹图¶

In [2]:
X = paddle.zeros((6, 6))
X[:, 0:3] = 1
print('输出图像矩阵:\n{}'.format(X)) # 输出图像矩阵
输出图像矩阵:
Tensor(shape=[6, 6], dtype=float32, place=Place(cpu), stop_gradient=True,
       [[1., 1., 1., 0., 0., 0.],
        [1., 1., 1., 0., 0., 0.],
        [1., 1., 1., 0., 0., 0.],
        [1., 1., 1., 0., 0., 0.],
        [1., 1., 1., 0., 0., 0.],
        [1., 1., 1., 0., 0., 0.]])

2.2 定义2×2的垂直边缘检测器(卷积核),并输出卷积运算的结果¶

In [3]:
W = paddle.to_tensor([[1,-1], [1,-1]])
out_conv = common.cross_correlation(X, W)
print('卷积后的输出:\n{}'.format(out_conv))
卷积后的输出:
Tensor(shape=[5, 5], dtype=float32, place=Place(cpu), stop_gradient=True,
       [[0., 0., 2., 0., 0.],
        [0., 0., 2., 0., 0.],
        [0., 0., 2., 0., 0.],
        [0., 0., 2., 0., 0.],
        [0., 0., 2., 0., 0.]])

2.3 执行池化函数输出最大池化结果¶

In [4]:
out_maxpooling = common.pool2D(out_conv, (2,2), 'max')
print('最大池化后的输出:\n{}'.format(out_maxpooling))
最大池化后的输出:
[[0. 2. 2. 0.]
 [0. 2. 2. 0.]
 [0. 2. 2. 0.]
 [0. 2. 2. 0.]]

2.4 执行池化函数输出均值池化结果¶

In [6]:
out_avgpooling = common.pool2D(out_conv, (2,2), 'avg')
print('均值池化后的输出:\n{}'.format(out_avgpooling))
均值池化后的输出:
[[0. 1. 1. 0.]
 [0. 1. 1. 0.]
 [0. 1. 1. 0.]
 [0. 1. 1. 0.]]

2.5 使用Paddle内置接口定义最大池化和均值池化函数,并输出结果¶

In [5]:
# 5.1 定义池化函数
max_pool = paddle.nn.MaxPool2D(kernel_size=2, stride=1)
mean_pool = paddle.nn.AvgPool2D(kernel_size=2, stride=1)
# 5.2 将卷积输入转换为Paddle规定的张量形态
out_conv = out_conv.reshape((1,1,out_conv.shape[0],out_conv.shape[1]))
# 5.3 执行池化运算
print('最大池化后的输出(API):{}'.format(max_pool(out_conv)))
print('均值池化后的输出(API):{}'.format(mean_pool(out_conv)))
最大池化后的输出(API):Tensor(shape=[1, 1, 4, 4], dtype=float32, place=Place(cpu), stop_gradient=True,
       [[[[0., 2., 2., 0.],
          [0., 2., 2., 0.],
          [0., 2., 2., 0.],
          [0., 2., 2., 0.]]]])
均值池化后的输出(API):Tensor(shape=[1, 1, 4, 4], dtype=float32, place=Place(cpu), stop_gradient=True,
       [[[[0., 1., 1., 0.],
          [0., 1., 1., 0.],
          [0., 1., 1., 0.],
          [0., 1., 1., 0.]]]])

6.6.3 填充和步幅¶

In [7]:
max_pool_stride2 = paddle.nn.MaxPool2D(kernel_size=2, stride=2)
print('最大池化后的输出(stride=2):{}'.format(max_pool_stride2(out_conv)))
最大池化后的输出(stride=2):Tensor(shape=[1, 1, 2, 2], dtype=float32, place=Place(cpu), stop_gradient=True,
       [[[[0., 2.],
          [0., 2.]]]])
In [7]:
max_pool_stride2 = paddle.nn.MaxPool2D(2)
print('最大池化后的输出(stride=2):{}'.format(max_pool_stride2(out_conv)))
最大池化后的输出(stride=2):Tensor(shape=[1, 1, 2, 2], dtype=float32, place=Place(cpu), stop_gradient=True,
       [[[[0., 2.],
          [0., 2.]]]])
In [9]:
max_pool_stride2_padding1 = paddle.nn.MaxPool2D(kernel_size=2, stride=2, padding=1)
print('最大池化后的输出(stride=2,padding=1):{}'.format(max_pool_stride2_padding1(out_conv)))
最大池化后的输出(stride=2,padding=1):Tensor(shape=[1, 1, 3, 3], dtype=float32, place=Place(cpu), stop_gradient=True,
       [[[[0., 2., 0.],
          [0., 2., 0.],
          [0., 2., 0.]]]])
In [11]:
max_pool_stride12_padding01 = paddle.nn.MaxPool2D(kernel_size=2, stride=(1,2), padding=(0,1))
print('最大池化后的输出(stride=2,padding=1):{}'.format(max_pool_stride12_padding01(out_conv)))
最大池化后的输出(stride=2,padding=1):Tensor(shape=[1, 1, 4, 3], dtype=float32, place=Place(cpu), stop_gradient=True,
       [[[[0., 2., 0.],
          [0., 2., 0.],
          [0., 2., 0.],
          [0., 2., 0.]]]])

6.6.4 多通道池化¶

In [10]:
# 将单通道卷积特征扩展为两通道的卷积特征图
out_conv_3D = paddle.concat((out_conv, out_conv+1), 1)
# 输出多通道最大池化
print('最大池化后的输出(3D):{}'.format(max_pool_stride2_padding1(out_conv_3D)))
最大池化后的输出(3D):Tensor(shape=[1, 2, 3, 3], dtype=float32, place=Place(cpu), stop_gradient=True,
       [[[[0., 2., 0.],
          [0., 2., 0.],
          [0., 2., 0.]],

         [[1., 3., 1.],
          [1., 3., 1.],
          [1., 3., 1.]]]])