• nn.maxpool2d
千次阅读
2021-08-10 09:18:20

引言

torch.nn.MaxPool2dtorch.nn.functional.max_pool2d，在pytorch构建模型中，都可以作为最大池化层的引入，但前者为类模块，后者为函数，在使用上存在不同。

1. torch.nn.functional.max_pool2d

pytorch中的函数，可以直接调用，源码如下：

def max_pool2d_with_indices(
input: Tensor, kernel_size: BroadcastingList2[int],
stride: Optional[BroadcastingList2[int]] = None,
padding: BroadcastingList2[int] = 0,
dilation: BroadcastingList2[int] = 1,
ceil_mode: bool = False,
return_indices: bool = False
) -> Tuple[Tensor, Tensor]:
r"""Applies a 2D max pooling over an input signal composed of several input
planes.

See :class:~torch.nn.MaxPool2d for details.
"""
if has_torch_function_unary(input):
return handle_torch_function(
max_pool2d_with_indices,
(input,),
input,
kernel_size,
stride=stride,
padding=padding,
dilation=dilation,
ceil_mode=ceil_mode,
return_indices=return_indices,
)
if stride is None:
stride = torch.jit.annotate(List[int], [])
return torch._C._nn.max_pool2d_with_indices(input, kernel_size, stride, padding, dilation, ceil_mode)

def _max_pool2d(
input: Tensor, kernel_size: BroadcastingList2[int],
stride: Optional[BroadcastingList2[int]] = None,
padding: BroadcastingList2[int] = 0,
dilation: BroadcastingList2[int] = 1,
ceil_mode: bool = False,
return_indices: bool = False
) -> Tensor:
if has_torch_function_unary(input):
return handle_torch_function(
max_pool2d,
(input,),
input,
kernel_size,
stride=stride,
padding=padding,
dilation=dilation,
ceil_mode=ceil_mode,
return_indices=return_indices,
)
if stride is None:
stride = torch.jit.annotate(List[int], [])
return torch.max_pool2d(input, kernel_size, stride, padding, dilation, ceil_mode)

max_pool2d = boolean_dispatch(
arg_name="return_indices",
arg_index=6,
default=False,
if_true=max_pool2d_with_indices,
if_false=_max_pool2d,
module_name=__name__,
func_name="max_pool2d",
)


使用如下：

import torch.nn.functional as F
input = torch.randn(20, 16, 50, 32)  # 输入张量
F.max_pool2d(input, kernel_size=2, stride=1,padding=0)
"""
其中：
Shape:
- Input: :math:(N, C, H_{in}, W_{in})
- Output: :math:(N, C, H_{out}, W_{out}), where
"""


2. torch.nn.MaxPool2d

pytorch中的类模块，先实例化，再调用其函数，源码如下（笔者已将源码中的注释简化）：

class MaxPool2d(_MaxPoolNd):

kernel_size: _size_2_t
stride: _size_2_t
padding: _size_2_t
dilation: _size_2_t

def forward(self, input: Tensor) -> Tensor:
return F.max_pool2d(input, self.kernel_size, self.stride,
self.padding, self.dilation, self.ceil_mode,
self.return_indices)


使用如下：

import torch
m = torch.nn.MaxPool2d(3, stride=2)  # 实例化
# 或者
m = torch.nn.MaxPool2d((3, 2), stride=(2, 1))  # 实例化
input = torch.randn(20, 16, 50, 32)  # 输入张量
output = m(input) # 使用该类
"""
Shape:
- Input: :math:(N, C, H_{in}, W_{in})
- Output: :math:(N, C, H_{out}, W_{out}), where
"""


3. 对比类和函数的使用

通过上述比较，torch.nn.functional.max_pool2d作为函数可以直接调用，传入参数（input（四个维度的输入张量）, kernel_size（卷积核尺寸）, stride（步幅）,padding（填充）, dilation, ceil_mode,return_indices）即可。
torch.nn.MaxPool2d，要先实例化，并在forward调用了torch.nn.functional.max_pool2d函数。
综上：torch.nn.functional.max_pool2d函数包含于torch.nn.MaxPool2d类模块中，可以单独使用，也可以实例化类再使用。
在模型构建下的使用：
（1）使用类模块

import torch
class Net(torch.nn.Module):
def __init__(self):
super(Net, self).__init__()
self.conv1 = torch.nn.Conv2d(1, 10, kernel_size=5)
self.conv2 = torch.nn.Conv2d(10, 20, kernel_size=5)
self.pooling = torch.nn.MaxPool2d(2)  # kernel_size = 2，实例化
self.fc = torch.nn.Linear(320, 10)

def forward(self, x):
# Flatten data from(n,1,28,28) to (n,784)
batch_size = x.s(0)
x = F.relu(self.pooling(self.conv1(x)))
x = F.relu(self.pooling(self.conv2(x)))
x = x.view(batch_size, -1)
x = self.fc(x)
return x


说明：kernel_size 是必须要指定的参数，否则会报错
笔者修改了torch.nn.MaxPool2d的源码，说明传入参数要求（记得改回来！）：

import torch
pooling1 = torch.nn.MaxPool2d(1,2,3,4)
print(pooling1)
pooling2 = torch.nn.MaxPool2d(1)
print(pooling2)


输出为

MaxPool2d(kernel_size=1, stride=2, padding=3, dilation=4, ceil_mode=False)
MaxPool2d(kernel_size=1, stride=1, padding=0, dilation=1, ceil_mode=False)


（2）直接调用函数

import torch
import torch.nn.functional as F
class Net(torch.nn.Module):
def __init__(self):
super(Net, self).__init__()
self.conv1 = torch.nn.Conv2d(1, 10, kernel_size=5)
self.conv2 = torch.nn.Conv2d(10, 20, kernel_size=5)
# 最大池化层无需实例化，直接在forward中调用
self.fc = torch.nn.Linear(320, 10)

def forward(self, x):
# Flatten data from(n,1,28,28) to (n,784)
batch_size = x.s(0)
x = F.relu(F.max_pool2d(self.conv1(x), kernel_size=2))  # 一定要指定kernel_size
x = F.relu(F.max_pool2d(self.conv2(x), kernel_size=2))
x = x.view(batch_size, -1)
x = self.fc(x)
return x

更多相关内容
• torch.nn.MaxPool2d详解

万次阅读 多人点赞 2020-11-22 20:18:38
之后我们验证一下 stride 参数： import torch import torch.nn as nn # 仅定义一个 3x3 的池化层窗口 m = nn.MaxPool2d(kernel_size=(3, 3), stride=(2, 2)) # 定义输入 # 四个参数分别表示 (batch_size, C_in, H_...

注意：这里展示的是本篇博文写时的版本最新的实现，但是后续会代码可能会迭代更新，建议对照官方文档进行学习。

先来看源码：

# 这个类是是许多池化类的基类，这里有必要了解一下
class _MaxPoolNd(Module):
__constants__ = ['kernel_size', 'stride', 'padding', 'dilation',
'return_indices', 'ceil_mode']
return_indices: bool
ceil_mode: bool
# 构造函数，这里只需要了解这个初始化函数即可。
def __init__(self, kernel_size: _size_any_t, stride: Optional[_size_any_t] = None,
padding: _size_any_t = 0, dilation: _size_any_t = 1,
return_indices: bool = False, ceil_mode: bool = False) -> None:
super(_MaxPoolNd, self).__init__()
self.kernel_size = kernel_size
self.stride = stride if (stride is not None) else kernel_size
self.padding = padding
self.dilation = dilation
self.return_indices = return_indices
self.ceil_mode = ceil_mode

def extra_repr(self) -> str:
return 'kernel_size={kernel_size}, stride={stride}, padding={padding}' \
', dilation={dilation}, ceil_mode={ceil_mode}'.format(**self.__dict__)

class MaxPool2d(_MaxPoolNd):
kernel_size: _size_2_t
stride: _size_2_t
padding: _size_2_t
dilation: _size_2_t

def forward(self, input: Tensor) -> Tensor:
return F.max_pool2d(input, self.kernel_size, self.stride,
self.padding, self.dilation, self.ceil_mode,
self.return_indices)


MaxPool2d 这个类的实现十分简单。

我们先来看一下基本参数，一共六个：

1. kernel_size ：表示做最大池化的窗口大小，可以是单个值，也可以是tuple元组
2. stride ：步长，可以是单个值，也可以是tuple元组
3. padding ：填充，可以是单个值，也可以是tuple元组
4. dilation ：控制窗口中元素步幅
5. return_indices ：布尔类型，返回最大值位置索引
6. ceil_mode ：布尔类型，为True，用向上取整的方法，计算输出形状；默认是向下取整。

关于 kernel_size 的详解

注意这里的 kernel_size 跟卷积核不是一个东西。 kernel_size 可以看做是一个滑动窗口，这个窗口的大小由自己指定，如果输入是单个值，例如 3 3 ，那么窗口的大小就是 3 × 3 3 \times 3 ，还可以输入元组，例如 (3, 2) ，那么窗口大小就是 3 × 2 3 \times 2

最大池化的方法就是取这个窗口覆盖元素中的最大值。

关于 stride 的详解

上一个参数我们确定了滑动窗口的大小，现在我们来确定这个窗口如何进行滑动。如果不指定这个参数，那么默认步长跟最大池化窗口大小一致。如果指定了参数，那么将按照我们指定的参数进行滑动。例如 stride=(2,3) ， 那么窗口将每次向右滑动三个元素位置，或者向下滑动两个元素位置。

关于 padding 的详解

这参数控制如何进行填充，填充值默认为0。如果是单个值，例如 1，那么将在周围填充一圈0。还可以用元组指定如何填充，例如 p a d d i n g = ( 2 , 1 ) padding=(2, 1) ，表示在上下两个方向个填充两行0，在左右两个方向各填充一列0。

关于 dilation 的详解

不会

关于 return_indices 的详解

这是个布尔类型值，表示返回值中是否包含最大值位置的索引。注意这个最大值指的是在所有窗口中产生的最大值，如果窗口产生的最大值总共有5个，就会有5个返回值。

关于 ceil_mode 的详解

这个也是布尔类型值，它决定的是在计算输出结果形状的时候，是使用向上取整还是向下取整。怎么计算输出形状，下面会讲到。一看就知道了。

——————————————参数解析结束分界线——————————————

最大池化层输出形状计算
H o u t = ⌊ H i n + 2 × p a d d i n g ⌊ 0 ⌋ − d i l a t i o n ⌊ 0 ⌋ × ( k e r n e l _ s i z e ⌊ 0 ⌋ − 1 ) − 1 s t r i d e ⌊ 0 ⌋ + 1 ⌋ H_{out}=\lfloor \frac{H_{in} + 2 \times padding\lfloor 0 \rfloor - dilation \lfloor 0 \rfloor \times (kernel\_size\lfloor 0 \rfloor - 1)-1}{stride\lfloor 0 \rfloor} + 1 \rfloor

W o u t = ⌊ W i n + 2 × p a d d i n g ⌊ 1 ⌋ − d i l a t i o n ⌊ 1 ⌋ × ( k e r n e l _ s i z e ⌊ 1 ⌋ − 1 ) − 1 s t r i d e ⌊ 1 ⌋ + 1 ⌋ W_{out}=\lfloor \frac{W_{in} + 2 \times padding\lfloor 1 \rfloor - dilation \lfloor 1 \rfloor \times (kernel\_size\lfloor 1 \rfloor - 1)-1}{stride\lfloor 1 \rfloor} + 1 \rfloor

看到向下取整的符号了吗？这个就是由 ceil_mode 控制的。

——————————————结束分界线——————————————

下面我们写代码验证一下最大池化层是如何计算的：

首先验证 kernel_size 参数

import torch
import torch.nn as nn

# 仅定义一个 3x3 的池化层窗口
m = nn.MaxPool2d(kernel_size=(3, 3))

# 定义输入
# 四个参数分别表示 (batch_size, C_in, H_in, W_in)
# 分别对应，批处理大小，输入通道数，图像高度（像素），图像宽度（像素）
# 为了简化表示，我们只模拟单张图片输入，单通道图片，图片大小是6x6
input = torch.randn(1, 1, 6, 6)

print(input)

output = m(input)

print(output)


结果：

第一个tensor是我们的输入数据 1 × 1 × 6 × 6 1 \times 1 \times 6 \times 6 ，我们画红线的区域就是我们设置的窗口大小 3 × 3 3 \times 3 ，背景色为红色的值，为该区域的最大值。

第二个tensor就是我们最大池化后的结果，跟我们标注的一模一样。

这个就是最基本的最大池化。

之后我们验证一下 stride 参数

import torch
import torch.nn as nn

# 仅定义一个 3x3 的池化层窗口
m = nn.MaxPool2d(kernel_size=(3, 3), stride=(2, 2))

# 定义输入
# 四个参数分别表示 (batch_size, C_in, H_in, W_in)
# 分别对应，批处理大小，输入通道数，图像高度（像素），图像宽度（像素）
# 为了简化表示，我们只模拟单张图片输入，单通道图片，图片大小是6x6
input = torch.randn(1, 1, 6, 6)

print(input)

output = m(input)

print(output)


结果：

红色的还是我们的窗口，但是我们的步长变为了2，可以看到第一个窗口和向右滑动后的窗口，他们的最大值刚好是重叠的部分都是2.688，向下滑动之后，最大值是0.8030，再次向右滑动，最大值是2.4859。

可以看到我们在滑动的时候省略了部分数值，因为剩下的数据不够一次滑动了，于是我们将他们丢弃了。

其实最后图片的宽度和高度还可以通过上面两个公式来计算，我们公式中用的是向下取整，因此我们丢弃了不足的数据。现在我们试试向上取整。

利用 ceil_mode 参数向上取整

import torch
import torch.nn as nn

# 仅定义一个 3x3 的池化层窗口
m = nn.MaxPool2d(kernel_size=(3, 3), stride=(2, 2), ceil_mode=True)

# 定义输入
# 四个参数分别表示 (batch_size, C_in, H_in, W_in)
# 分别对应，批处理大小，输入通道数，图像高度（像素），图像宽度（像素）
# 为了简化表示，我们只模拟单张图片输入，单通道图片，图片大小是6x6
input = torch.randn(1, 1, 6, 6)

print(input)

output = m(input)

print('\n\n\n\n\n')

print(output)


结果：

从结果可以看出，输出的size由原来的 2 × 2 2 \times 2 变成了现在的 3 × 3 3 \times 3 。这就是向上取整的结果。为什么会出现这样的结果呢？

这看起来像是我们对输入进行了填充，但是这个填充值不会参与到计算最大值中。

继续验证 padding 参数

import torch
import torch.nn as nn

# 仅定义一个 3x3 的池化层窗口
m = nn.MaxPool2d(kernel_size=(3, 3), stride=(3, 3), padding=(1, 1))

# 定义输入
# 四个参数分别表示 (batch_size, C_in, H_in, W_in)
# 分别对应，批处理大小，输入通道数，图像高度（像素），图像宽度（像素）
# 为了简化表示，我们只模拟单张图片输入，单通道图片，图片大小是6x6
input = torch.randn(1, 1, 6, 6)

print(input)

output = m(input)

print('\n\n')

print(output)


结果：

我们对周围填充了一圈0，我们滑动窗口的范围就变化了，这就是填充的作用。

但是有一点需要注意，就是即使我们填充了0，这个0也不会被选为最大值。例如上图的左上角四个数据，如果我们全部变为负数，结果是-0.1711，而不会是我们填充的0值，这一点要注意。

最后验证 return_indices 参数：

import torch
import torch.nn as nn

# 仅定义一个 3x3 的池化层窗口
m = nn.MaxPool2d(kernel_size=(3, 3), return_indices=True)

# 定义输入
# 四个参数分别表示 (batch_size, C_in, H_in, W_in)
# 分别对应，批处理大小，输入通道数，图像高度（像素），图像宽度（像素）
# 为了简化表示，我们只模拟单张图片输入，单通道图片，图片大小是6x6
input = torch.randn(1, 1, 6, 6)

print(input)

output = m(input)

print(output)


结果：

仅仅是多返回了一个位置信息。元素位置从0开始计数，6表示第7个元素，9表示第10个元素…需要注意的是，返回值实际上是多维的数据，但是我们只看相关的元素位置信息，忽略维度的问题。

最后一个参数 dilation ，不会

展开全文
• 卷积神经网络中nn.Conv2d()和nn.MaxPool2d() 卷积神经网络之Pythorch实现： nn.Conv2d()就是PyTorch中的卷积模块 参数列表 参数 作用 in_channels 输入数据体的深度 out_channels 输出数 据体的深度 ...

卷积神经网络中nn.Conv2d()和nn.MaxPool2d()

卷积神经网络之Pythorch实现：

nn.Conv2d()就是PyTorch中的卷积模块

参数列表

参数作用
in_channels输入数据体的深度
out_channels输出数 据体的深度
kernel_size滤波器（卷积核）的大小 注1
stride滑动的步长
padding零填充的圈数 注2
bias是否启用偏置，默认是True，代表启用
groups输出数据体深度上和输入数 据体深度上的联系 注3
dilation卷积对于输入数据体的空间间隔 注4

注：1. 可以使用一 个数字来表示高和宽相同的卷积核，比如 kernel_size=3，也可以使用 不同的数字来表示高和宽不同的卷积核，比如 kernel_size=(3, 2)；

1. padding=0表示四周不进行零填充，而 padding=1表示四周进行1个像素点的零填充；

2. groups表示输出数据体深度上和输入数 据体深度上的联系，默认 groups=1，也就是所有的输出和输入都是相 关联的，如果 groups=2，这表示输入的深度被分割成两份，输出的深 度也被分割成两份，它们之间分别对应起来，所以要求输出和输入都 必须要能被 groups整除。

3. 默认dilation=1详情见 nn.Conv2d()中dilation参数的作用或者CSDN

nn.MaxPool2d()表示网络中的最大值池化

参数列表：

参数作用
kernel_size与上面nn.Conv2d()相同
stride与上面nn.Conv2d()相同
padding与上面nn.Conv2d()相同
dilation与上面nn.Conv2d()相同
return_indices表示是否返回最大值所处的下标，默认 return_indices=False
ceil_mode表示使用一些方格代替层结构，默认 ceil_mode=False

注：一般不会去设置return_indicesceil_mode参数

import torch.nn as nn

class SimpleCNN(nn.Module):
def __init__(self):
super(SimpleCNN, self).__init__()
layer1 = nn.Sequential()
# 把一个三通道的照片RGB三个使用32组卷积核卷积，每组三个卷积核，组内卷积后相加得出32组输出
layer1.add_module('conv1', nn.Conv2d(3, 32, (3, 3), (1, 1), padding=1))
layer1.add_module('relu1', nn.ReLU(True))
layer1.add_module('pool1', nn.MaxPool2d(2, 2))
self.layer1 = layer1

layer2 = nn.Sequential()
layer2.add_module('conv2', nn.Conv2d(32, 64, (3, 3), (1, 1), padding=1))
layer2.add_module('relu2', nn.ReLU(True))
layer2.add_module('pool2', nn.MaxPool2d(2, 2))
self.layer2 = layer2

layer3 = nn.Sequential()
layer3.add_module('conv3', nn.Conv2d(64, 128, (3, 3), (1, 1), padding=1))
layer3.add_module('relu3', nn.ReLU(True))
layer3.add_module('pool3', nn.MaxPool2d(2, 2))
self.layer3 = layer3

layer4 = nn.Sequential()
layer4.add_module('fc1', nn.Linear(2048, 512))
layer4.add_module('fc_relu1', nn.ReLU(True))
layer4.add_module('fc2', nn.Linear(512, 64))
layer4.add_module('fc_relu2', nn.ReLU(True))
layer4.add_module('f3', nn.Linear(64, 10))
self.layer4 = layer4

def forward(self, x):
conv1 = self.layer1(x)
conv2 = self.layer2(conv1)
conv3 = self.layer3(conv2)
fc_input = conv3.view(conv3.size(0), -1)
fc_out = self.layer4(fc_input)
return fc_out

model = SimpleCNN()
print(model)


输出

SimpleCNN(
(layer1): Sequential(
(conv1): Conv2d(3, 32, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(relu1): ReLU(inplace=True)
(pool1): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
)
(layer2): Sequential(
(conv2): Conv2d(32, 64, kernel_size=(3, 3), stride=(1, 1))
(relu2): ReLU(inplace=True)
(pool2): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
)
(layer3): Sequential(
(conv3): Conv2d(64, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(relu3): ReLU(inplace=True)
(pool3): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
)
(layer4): Sequential(
(fc1): Linear(in_features=2048, out_features=512, bias=True)
(fc_relu1): ReLU(inplace=True)
(fc2): Linear(in_features=512, out_features=64, bias=True)
(fc_relu2): ReLU(inplace=True)
(f3): Linear(in_features=64, out_features=10, bias=True)
)
)


提取模型的层级结构

提取层级结构可以使用以下几个nn.Model的属性，第一个是children()属性，它会返回下一级模块的迭代器，在上面这个模型中，它会返回在self.layer1，self.layer2，self.layer4上的迭代器而不会返回它们内部的东西；modules()
会返回模型中所有的模块的迭代器，这样它就能访问到最内层，比如self.layer1.conv1这个模块；还有一个与它们相对应的是name_children()属性以及named_modules()，这两个不仅会返回模块的迭代器，还会返回网络层的名字。

提取出model中的前两层

nn.Sequential(*list(model.children())[:2])


输出：

Sequential(
(0): Sequential(
(conv1): Conv2d(3, 32, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(relu1): ReLU(inplace=True)
(pool1): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
)
(1): Sequential(
(conv2): Conv2d(32, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(relu2): ReLU(inplace=True)
(pool2): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
)
)


提取出model中的所有卷积层

conv_model = nn.Sequential()
for layer in model.named_modules():
if isinstance(layer[1], nn.Conv2d):
conv_model.add_module(layer[0].split('.')[1] ,layer[1])
print(conv_model)


输出：

Sequential(
(conv1): Conv2d(3, 32, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(conv2): Conv2d(32, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(conv3): Conv2d(64, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
)


提取网络参数并对其初始化

nn.Moudel里面有两个特别重要的关于参数的属性，分别是named_parameters()parameters()。前者会输出网络层的名字和参数的迭代器，后者会给出一个网络的全部参数的迭代器。

for param in model.named_parameters():
print(param[0])
# print(param[1])


输出：

layer1.conv1.weight
layer1.conv1.bias
layer2.conv2.weight
layer2.conv2.bias
layer3.conv3.weight
layer3.conv3.bias
layer4.fc1.weight
layer4.fc1.bias
layer4.fc2.weight
layer4.fc2.bias
layer4.f3.weight
layer4.f3.bias


主流神经网络案例分析

案例：使用卷积神经网络实现对Minist数据集的预测

import matplotlib.pyplot as plt
import torch.utils.data
import torchvision.datasets
import os
import torch.nn as nn
from torchvision import transforms

class CNN(nn.Module):
def __init__(self):
super(CNN, self).__init__()
self.layer1 = nn.Sequential(
nn.Conv2d(1, 16, kernel_size=(3, 3)),
nn.BatchNorm2d(16),
nn.ReLU(inplace=True),
)

self.layer2 = nn.Sequential(
nn.Conv2d(16, 32, kernel_size=(3, 3)),
nn.BatchNorm2d(32),
nn.ReLU(inplace=True),
nn.MaxPool2d(kernel_size=2, stride=2),
)

self.layer3 = nn.Sequential(
nn.Conv2d(32, 64, kernel_size=(3, 3)),
nn.BatchNorm2d(64),
nn.ReLU(inplace=True)
)

self.layer4 = nn.Sequential(
nn.Conv2d(64, 128, kernel_size=(3, 3)),
nn.BatchNorm2d(128),
nn.ReLU(inplace=True),
nn.MaxPool2d(kernel_size=2, stride=2)
)

self.fc = nn.Sequential(
nn.Linear(128 * 4 * 4, 1024),
nn.ReLU(inplace=True),
nn.Linear(1024, 128),
nn.Linear(128, 10)
)

def forward(self, x):
x = self.layer1(x)
x = self.layer2(x)
x = self.layer3(x)
x = self.layer4(x)
x = x.view(x.size(0), -1)
x = self.fc(x)
return x

os.environ["KMP_DUPLICATE_LIB_OK"] = "TRUE"

data_tf = transforms.Compose(
[transforms.ToTensor(),
transforms.Normalize([0.5], [0.5])]
)

train_dataset = torchvision.datasets.MNIST(root='F:/机器学习/pytorch/书/data/mnist', train=True,
transform=data_tf, download=True)

test_dataset = torchvision.datasets.MNIST(root='F:/机器学习/pytorch/书/data/mnist', train=False,
transform=data_tf, download=True)

batch_size = 100
train_loader = torch.utils.data.DataLoader(
dataset=train_dataset, batch_size=batch_size
)

test_loader = torch.utils.data.DataLoader(
dataset=test_dataset, batch_size=batch_size
)

model = CNN()
model = model.cuda()
criterion = nn.CrossEntropyLoss()
criterion = criterion.cuda()
optimizer = torch.optim.Adam(model.parameters())

# 节约时间，三次够了
iter_step = 3
loss1 = []
loss2 = []
for step in range(iter_step):
loss1_count = 0
loss2_count = 0
for images, labels in train_loader:
images = images.cuda()
labels = labels.cuda()
images = images.reshape(-1, 1, 28, 28)
output = model(images)
pred = output.squeeze()

optimizer.zero_grad()
loss = criterion(pred, labels)
loss.backward()
optimizer.step()

_, pred = torch.max(pred, 1)

loss1_count += int(torch.sum(pred == labels)) / 100
# 测试
else:
test_loss = 0
accuracy = 0
with torch.no_grad():
for images, labels in test_loader:
images = images.cuda()
labels = labels.cuda()
pred = model(images.reshape(-1, 1, 28, 28))
_, pred = torch.max(pred, 1)
loss2_count += int(torch.sum(pred == labels)) / 100

loss1.append(loss1_count / len(train_loader))
loss2.append(loss2_count / len(test_loader))

print(f'第{step}次训练：训练准确率：{loss1[len(loss1)-1]}，测试准确率：{loss2[len(loss2)-1]}')

plt.plot(loss1, label='Training loss')
plt.plot(loss2, label='Validation loss')
plt.legend()


输出：

第0次训练：训练准确率：0.9646166666666718，测试准确率：0.9868999999999996
第1次训练：训练准确率：0.9865833333333389，测试准确率：0.9908999999999998
第2次训练：训练准确率：0.9917000000000039，测试准确率：0.9879999999999994
<matplotlib.legend.Legend at 0x21f03092fd0>


展开全文
• torch.nn.MaxPool2d参数详解

千次阅读 2021-09-05 10:28:12
MaxPool2d的使用方法。 API官网文档 MaxPool2d 参数介绍 kernel_size ：表示做最大池化的窗口大小，可以是单个值，也可以是tuple元组 stride ：步长，可以是单个值，也可以是tuple元组 padding ：填充，可以是...

在神经网络中 池化层是比较重要的，是提取重要信息的操作，可以去掉不重要的信息，减少计算开销。下面我们来介绍
MaxPool2d的使用方法。

API官网文档

MaxPool2d 参数介绍

• kernel_size ：表示做最大池化的窗口大小，可以是单个值，也可以是tuple元组
• stride ：步长，可以是单个值，也可以是tuple元组
• padding ：填充，可以是单个值，也可以是tuple元组
• dilation ：控制窗口中元素步幅
• return_indices ：布尔类型，返回最大值位置索引
• ceil_mode ：布尔类型，为True，用向上取整的方法，计算输出形状；默认是向下取整。

kernel_size 的详解

注意这里的 kernel_size 跟卷积核不是一个东西。 kernel_size 可以看做是一个滑动窗口，这个窗口的大小由自己指定，如果输入是单个值，例如 3 ，那么窗口的大小就是 3 × 3 3 ，还可以输入元组，例如 (3, 2) ，那么窗口大小就是 3 × 2。
最大池化的方法就是取这个窗口覆盖元素中的最大值

stride 的详解

上一个参数我们确定了滑动窗口的大小，现在我们来确定这个窗口如何进行滑动。如果不指定这个参数，那么默认步长跟最大池化窗口大小一致。如果指定了参数，那么将按照我们指定的参数进行滑动。例如 stride=(2,3) ， 那么窗口将每次向右滑动三个元素位置，或者向下滑动两个元素位置

padding 的详解

这参数控制如何进行填充，填充值默认为0。如果是单个值，例如 1，那么将在周围填充一圈0。还可以用元组指定如何填充，例如 padding = ( 2 , 1 ) padding=(2, 1)padding=(2,1) ，表示在上下两个方向个填充两行0，在左右两个方向各填充一列0。

dilation 的详解

空洞卷积，默认 dilation=1，如果kernel_size =3，那么卷积核就是33的框。如果dilation = 2，kernel_size =3，那么每列数据与每列数据中间再加一列空洞，那么卷积核就变成55的框。

return_indices 的详解

这是个布尔类型值，表示返回值中是否包含最大值位置的索引。注意这个最大值指的是在所有窗口中产生的最大值，如果窗口产生的最大值总共有5个，就会有5个返回值。

ceil_mode 的详解

这个也是布尔类型值，它决定的是在计算输出结果形状的时候，是使用向上取整还是向下取整。怎么计算输出形状，下面会讲到。一看就知道了。

最大池化层输出形状计算

看到向下取整的符号了吗？这个就是由 ceil_mode 控制的。

参数示例介绍

验证 kernel_size 参数

import torch
import torch.nn as nn

# 仅定义一个 3x3 的池化层窗口
m = nn.MaxPool2d(kernel_size=(3, 3))

# 定义输入
# 四个参数分别表示 (batch_size, C_in, H_in, W_in)
# 分别对应，批处理大小，输入通道数，图像高度（像素），图像宽度（像素）
# 为了简化表示，我们只模拟单张图片输入，单通道图片，图片大小是6x6
input = torch.randn(1, 1, 6, 6)

print(input)

output = m(input)

print(output)



第一个tensor是我们的输入数据 1 × 1 × 6 × 6 ，我们画红线的区域就是我们设置的窗口大小 3 × 3 ，背景色为红色的值，为该区域的最大值。

第二个tensor就是我们最大池化后的结果，跟我们标注的一模一样。

验证一下 stride 参数

import torch
import torch.nn as nn

# 仅定义一个 3x3 的池化层窗口
m = nn.MaxPool2d(kernel_size=(3, 3), stride=(2, 2))

# 定义输入
# 四个参数分别表示 (batch_size, C_in, H_in, W_in)
# 分别对应，批处理大小，输入通道数，图像高度（像素），图像宽度（像素）
# 为了简化表示，我们只模拟单张图片输入，单通道图片，图片大小是6x6
input = torch.randn(1, 1, 6, 6)

print(input)

output = m(input)

print(output)



红色的还是我们的窗口，但是我们的步长变为了2，可以看到第一个窗口和向右滑动后的窗口，他们的最大值刚好是重叠的部分都是2.688，向下滑动之后，最大值是0.8030，再次向右滑动，最大值是2.4859。

可以看到我们在滑动的时候省略了部分数值，因为剩下的数据不够一次滑动了，于是我们将他们丢弃了。

其实最后图片的宽度和高度还可以通过上面两个公式来计算，我们公式中用的是向下取整，因此我们丢弃了不足的数据。现在我们试试向上取整。

利用 ceil_mode 参数向上取整

import torch
import torch.nn as nn

# 仅定义一个 3x3 的池化层窗口
m = nn.MaxPool2d(kernel_size=(3, 3), stride=(2, 2), ceil_mode=True)

# 定义输入
# 四个参数分别表示 (batch_size, C_in, H_in, W_in)
# 分别对应，批处理大小，输入通道数，图像高度（像素），图像宽度（像素）
# 为了简化表示，我们只模拟单张图片输入，单通道图片，图片大小是6x6
input = torch.randn(1, 1, 6, 6)

print(input)

output = m(input)

print('\n\n\n\n\n')

print(output)



从结果可以看出，输出的size由原来的 2 × 2 变成了现在的 3 × 3。这就是向上取整的结果。为什么会出现这样的结果呢？

这看起来像是我们对输入进行了填充，但是这个填充值不会参与到计算最大值中

验证 padding 参数

import torch
import torch.nn as nn

# 仅定义一个 3x3 的池化层窗口
m = nn.MaxPool2d(kernel_size=(3, 3), stride=(3, 3), padding=(1, 1))

# 定义输入
# 四个参数分别表示 (batch_size, C_in, H_in, W_in)
# 分别对应，批处理大小，输入通道数，图像高度（像素），图像宽度（像素）
# 为了简化表示，我们只模拟单张图片输入，单通道图片，图片大小是6x6
input = torch.randn(1, 1, 6, 6)

print(input)

output = m(input)

print('\n\n')

print(output)



我们对周围填充了一圈0，我们滑动窗口的范围就变化了，这就是填充的作用。

但是有一点需要注意，就是即使我们填充了0，这个0也不会被选为最大值。例如上图的左上角四个数据，如果我们全部变为负数，结果是-0.1711，而不会是我们填充的0值，这一点要注意。

验证 return_indices 参数

import torch
import torch.nn as nn

# 仅定义一个 3x3 的池化层窗口
m = nn.MaxPool2d(kernel_size=(3, 3), return_indices=True)

# 定义输入
# 四个参数分别表示 (batch_size, C_in, H_in, W_in)
# 分别对应，批处理大小，输入通道数，图像高度（像素），图像宽度（像素）
# 为了简化表示，我们只模拟单张图片输入，单通道图片，图片大小是6x6
input = torch.randn(1, 1, 6, 6)

print(input)

output = m(input)

print(output)



验证 dilation 参数


python
import torch
import torch.nn as nn

# 仅定义一个 3x3 的池化层窗口
m = nn.MaxPool2d(kernel_size=(3, 3),dilation=2)

# 定义输入
# 四个参数分别表示 (batch_size, C_in, H_in, W_in)
# 分别对应，批处理大小，输入通道数，图像高度（像素），图像宽度（像素）
# 为了简化表示，我们只模拟单张图片输入，单通道图片，图片大小是6x6
input = torch.randn(1, 1, 6, 6)

print(input)

output = m(input)

print(output)
`

参考文档: https://blog.csdn.net/weixin_38481963/article/details/109962715

展开全文
• class torch.nn.MaxPool2d(kernel_size, stride=None, padding=0, dilation=1, return_indices=False, ceil_mode=False) 如下是MaxPool2d的解释： class MaxPool2d(_MaxPoolNd): r"""Applies a 2D max pooling over...
• torch.nn.MaxPool2d和torch.nn.functional.max_pool2d两者本质上是一样的，具体可以参考torch.nn.MaxPool2d的源代码，核心源代码如下所示： from .. import functional as F class MaxPool2d(_MaxPoolNd): kernel_...
• Pytorch nn.MaxPool1d； nn.functional.max_pool1d pytorch 中nn.MaxPool1d() 和nn.MaxPool2d()对比
• 1.tf.nn.maxpool2d()函数介绍 tf.nn.max_pool2d(input, ksize, strides, padding, data_format='NHWC', name=None) 参数说明： Args input A 4-DTensorof the format specified bydata_format. ...
• 作者主页(文火冰糖的硅基工坊)：文火冰糖（王文兵）的博客_文火冰糖的硅基工坊_CSDN博客 ...本文是深度学习框架 pytorch 的API ： torch.nn.MaxPool2d() 函数的用法。 本博客介绍了 torch.nn.MaxPool2...
• Pytorch学习笔记(四):nn.MaxPool2d()函数详解

千次阅读 多人点赞 2021-06-16 15:48:48
相关文章 Pytorch学习笔记(一):torch.cat()模块的详解 文章目录1.函数语法格式和作用2.参数解释3.... 1.函数语法格式和作用 ...MaxPool2d(kernel_size, stride=None, padding=0, dilation=1, return_
• torch.nn.MaxPool2d 功能： MaxPool 最大池化层，池化层在卷积神经网络中的作用在于特征融合和降维。池化也是一种类似的卷积操作，只是池化层的所有参数都是超参数，是学习不到的。 作用： maxpooling有局部不变性...
• torch.nn.MaxPool2d

万次阅读 多人点赞 2020-07-28 15:57:52
class torch.nn.MaxPool2d(kernel_size, stride=None, padding=0, dilation=1, return_indices=False, ceil_mode=False) 如果padding不是0，会在输入的每一边添加相应数目0 比如padding=1，则在每一边分别补0. ...
• Pytorch中卷积使用的一些总结torch.nnnn.Conv2dnn.maxpool2dnn.Avg_pool空间金字塔池化（Spatial Pyramid Pooling）卷积神经网络——输入层、卷积层、激活函数、池化层、全连接层 torch.nn nn.Conv2d   nn.Conv2d ...
• torch nn.MaxPool2d

2020-08-22 17:42:09
1.应用 import torch import torch.nn as nn m = nn.MaxPool2d(2) ...CLASS torch.nn.MaxPool2d(kernel_size: Union[T, Tuple[T, ...]], stride: Optional[Union[T, Tuple[T, ...]]] = None, padding: Union
• 这里写目录标题一、nn.Sequential二、nn.Conv2d 一、nn.Sequential torch.nn.Sequential是一个Sequential容器，模块将按照构造函数中传递的顺序添加到模块中。另外，也可以传入一个有序模块。 为了更容易理解，官方...
• nn.MaxPool2d(kernel_size=2, stride=(2, 1), padding=(0, 0))， 这样在用交叉熵做损失函数的时候，有时候会出现loss为nan的情况，检查的时候发现，某些样本的提取出来的feature全为nan。 以上这篇浅谈pytorch池化...
• torch.nn.MaxPool2d()学习笔记

千次阅读 2020-12-21 15:13:08
参考链接: torch.nn.MaxPool2d(kernel_size, stride=None, padding=0, dilation=1, return_indices=False, ceil_mode=False) 参考链接: Convolution arithmetic 参考链接: 神经网络与深度学习 参考链接: 二维转置...
• 使用最大值操作的池化层被称之为最大池化层（max pooling），使用平均值操作的池化层称之为平均池化层（average pooling），总的来说，池化层的作用是可以压缩数据和参数的量， 减小过拟合。 如下
• 1. nn.Conv2d nn.Conv2d 输入信号的形式为(N, Cin, H, W), N表示batch size，Cin​表示channel个数，H，W分别表示特征图的高和宽。 参数说明： stride(步长)：控制cross-correlation的步长，可...
• pytorch 池化层——最大值池化nn.MaxPool 2dnn.MaxPool1d nn.MaxPool1d函数参数例子计算过程nn.MaxPool2d函数参数例子计算过程 nn.MaxPool1d 函数 class torch.nn.MaxPool1d(kernel_size, stride=None, padding=0, ...
• 首先是pytorch中的卷积 nn.Conv2d 我们可以查看官方文档。 nn.Conv2d 输入信号的形式为(N,Cin,H,W),N表示batch size，Cin​表示channel个数，H，W分别表示特征图的高和宽。 参数说明： stride(步长)：控制cross...
• pytorch 中nn.MaxPool1d() 和nn.MaxPool2d()对比
• tf.nn.max_pool(value, ksize, strides, padding, name=None) 参数是四个，和卷积很类似： 第一个参数value：需要池化的输入，一般池化层接在卷积层后面，所以输入通常是feature map，依然是[batch, height, width, ...
• 本文主要讲解torch.mean()、torch.max() 和 nn.AdaptiveAvgPool2d()、nn.AdaptiveMaxPool2d() 这四个函数的基本用法以及区别
• tf.nn.max_pool 原生的池化操作，而tf.layers.max_pooling2d是进行了封装，对许多参数进行了设置，使用起来更方便 tf.layers.max_pooling2d： 用于2D输入的最大池化层(例如图像). 参数： inputs：池的张量,秩...
• 一、 如果在做卷积过程中出现WARNING:tensorflow:From D:\Anaconda3\lib\site-packages\keras\backend\tensorflow_backend.py:4070: The name tf.... Please use tf.nn.max_pool2d instead.**** ，就是如下图所示的...
• 最近在研究学习TensorFlow，在做识别手写数字时，遇到了tf.nn.conv2d这个方法，其中有些方法还不是很清楚，于是网上搜索后，记录如下： 卷积神经网络的核心是对图像的“卷积”操作 tf.nn.conv2d方法定义 tf.nn....
• torch学习三之nn.Maxpool1dMaxpool1DMaxpool2D Maxpool1D 函数原型： torch.nn.MaxPool1d(kernel_size: Union[T, Tuple[T, ...]], stride: Optional[Union[T, Tuple[T, ...]]] = None, padding: Union[T, Tuple[T,...
• 1 tf.nn.max_pool( 2 value, 3 ksize, 4 strides, 5 padding, 6 data_format='NHWC', 7 name=None 8 ) 池化与卷积差不多（个人认为！），原因在于池化类似于亚采样。 1 tf.layers.max_pooling2d( 2 ...

...