在学习pytorch的过程中,看到一些代码的解释中会说这个网络的期望输入大小为32x32(也可能是其他数字),请将输入图片调整为32x32。 开始的时候有一些不解,仔细看代码后明白,为代码条理清晰,一些神经网络结构事先被定义好,当卷积神经网络中包含有全连接层时,由于全连接层被设置为是固定尺寸的输入输出,全连接层的输入与输入图像尺寸息息相关,故定义好网络结构后,输入图像尺寸亦随之确定。 所以在用pytorch编写神经网络结构时,尤其是卷积神经网络,要特别注意输入图像的尺寸,如果想套用某个网络结构,需要先通过网络结构计算出输入图像尺寸,将自己的图像调整为所需要的尺寸;当然还可以根据自己的图像尺寸适当调整网络结构。以下是具体操作方法。
分析神经网络结构
示例:
class ConvNet(nn.Module):
def __init__(self):
super().__init__()
# 1,28x28
self.conv1=nn.Conv2d(1,10,5) # 24x24
self.pool = nn.MaxPool2d(2,2) # 12x12
self.conv2=nn.Conv2d(10,20,3) # 10x10
self.fc1 = nn.Linear(20*10*10,500)
self.fc2 = nn.Linear(500,10)
def forward(self,x):
in_size = x.size(0)
out = self.conv1(x) #24
out = F.relu(out)
out = self.pool(out) #12
out = self.conv2(out) #10
out = F.relu(out)
out = out.view(in_size,-1)
out = self.fc1(out)
out = F.relu(out)
out = self.fc2(out)
out = F.log_softmax(out,dim=1)
return out
在写代码时,尽量将每一层的输入输出尺寸标注出来,以便后续阅读。
首先介绍Conv2d、max_pool2d的参数:
torch.nn.Conv2d(in_channels, out_channels, kernel_size, stride=1, padding=0,
dilation=1, groups=1, bias=True)
in_channels:输入通道数
out_channels:输出通道数(卷积核的个数)
kernel_size:卷积核的尺寸
stride:卷积步长(默认值为1)
padding:输入在每一条边补充0的层数(默认不补充)
dilation:卷积核元素之间的间距(默认值为1)
groups:从输入通道到输出通道的阻塞连接数(默认值是1)
bias:是否添加偏置(默认是True)
torch.nn.MaxPool2d(kernel_size, stride=None, padding=0, dilation=1, return_indices=False, ceil_mode=False)
kernel_size:池化的窗口大小
stride:窗口移动的步长,默认值是kernel_size
padding:输入的每一条边补充0的层数
dilation:一个控制窗口中元素步幅的参数
return_indices:如果等于True,会返回输出最大值的序号,对于上采样操作会有帮助
ceil_mode:如果等于True,计算输出信号大小的时候,会使用向上取整,代替默认的向下取整的操作
接下来通过网络结构分析每层输出尺寸大小:
重要公式:边长为n的图像,经过卷积核尺寸大小为k,步长为s的卷积,得到边长为1+(n-k)/s的图像
举例说明:
分析一下代码的输出尺寸:
class ConvNet(nn.Module):
def __init__(self):
super().__init__()
# 1,28x28
self.conv1=nn.Conv2d(1,10,5) # 24x24
self.pool = nn.MaxPool2d(2,2) # 12x12
self.conv2=nn.Conv2d(10,20,3) # 10x10
self.fc1 = nn.Linear(20*10*10,500)
self.fc2 = nn.Linear(500,10)
def forward(self,x):
in_size = x.size(0)
out = self.conv1(x) #24
out = F.relu(out)
out = self.pool(out) #12
out = self.conv2(out) #10
out = F.relu(out)
out = out.view(in_size,-1)
out = self.fc1(out)
out = F.relu(out)
out = self.fc2(out)
out = F.log_softmax(out,dim=1)
return out
为了清晰分析,在编写神经网络结构的代码时,最好将会使输入输出改变的结构(例如本例的卷积层和池化层),在前面定义出来。 如果读别人已写好的代码时,一定要结合前向传播的结构来分析,不能只看代码的上面部分,因为神经网络的结构中,可能还含有其他能改变图像尺寸的结构。在上述代码中,只有以下代码部分会改变输出图像尺寸大小。
# 1,28x28
self.conv1=nn.Conv2d(1,10,5) # 24x24
self.pool = nn.MaxPool2d(2,2) # 12x12
self.conv2=nn.Conv2d(10,20,3) # 10x10
self.fc1 = nn.Linear(20*10*10,500)
self.fc2 = nn.Linear(500,10)
假设输入图像尺寸为28x28
第一层卷积卷积核尺寸大小为5x5,步长为1。所以输出图像尺寸:1+(28-5)/1=24
即代码第二行注释标注:经过第一层卷积层后,输出图像尺寸变为24x24
同理,在池化层,池化窗口大小为2x2,移动步长为2,所以经过池化层后,输出图像尺寸变为12x12
第二层卷积尺寸大小为3x3,步长为1,所以输出图像尺寸:1+(12-3)/1=10
经过第二层卷积后,输出图像尺寸为10x10,输出维度为20,所以全连接层的输入固定为201010
所以此网络只接受输入图像尺寸为28x28。
如果,不想改变输入图像的尺寸,可以通过以上步骤,计算出全连接层的输入,适当改变神经网络结构,已达到理想的效果。
现在很多卷积神经网络模型,都用卷积层替代全连接层,就是因为这个原因。因为全连接层的参数的尺寸与输入图像的尺寸有关,故输入图像尺寸改变,模型参数初始化尺寸亦改变。若采用卷积层替代全连接层,则输入图像尺寸改变,模型不用做任何改变。
————————————————
转载自:https://blog.csdn.net/weixin_43423455/article/details/99096580