1 前言
经过前面三篇文章的介绍,我们已经知道了卷积的原理、卷积的计算过程以及池化的原理和过程等。在接下来的这篇文章中,笔者将开始介绍如何通过Pytorch这一深度学习框架来实现卷积和池化的操作,以及各个API的使用介绍和说明。最后,笔者还会介绍卷积神经网络的入门级网络结构LeNet5,我们也将会通过LeNet5这个网络来完成fashion mnist数据集的分类任务。
2 API接口介绍
在Pytorch中,对于网络中的一些基本功能函数(例如:卷积、池化、激活函数等)都被放在了torch.nn.functional
这个模块中。因此,为了方便后续的使用,按惯例我们都会以import torch.nn.functional as F
的方式来导入各类基本功能函数,然后以F.
的方式来进行调用。
2.1 卷积操作
在介绍如何使用卷积这一功能函数前,我们先来介绍一下Pytorch中如何表示(类)图像数据。在Pytorch(tensorflow)中,都是通过四个维度来对图像数据进行表示,分别是:样本个数(batch_size)、高度(heigh)、宽度(width)和通道数(channel)。但是对于不同的深度学习框架来说,其在这个维度上的默认顺序并不一样。在Pytorch中,这四个维度的顺序为[batch_size,channels,heigh,width]
;但是在tensorflow中,这一顺序却为[batch_size,heigh,width,channels]
。可以看出,两者仅仅是把通道数这一维度放到了不同的位置上。
同样的,对于卷积核来说也需要用四个维度来进行表示,分别是:高度(heigh)、宽度(width)、上一层输入的通道数(in_channels)和输出特征图的通道数(卷积核个数)(out_channels)。在Pytorch中,这四个维度的顺序为[out_channels,in_channels,heigh,width]
;而在tensorflow中,这一顺序却是[heigh,width,in_channels,out_channels]
。所以,需要注意的就是在使用不同的深度学习框架时一定要弄清楚输入数据的形式。
2.1.1 单卷积核卷积
如图1所示,在上一篇文章中我们以该图中的示例介绍了如何手动的来计算卷积的结果,现在我们看看如何通过框架来进行计算。
首先我们需要将卷入和卷积核这两个变量给定义出来:
inputs = torch.tensor([0, 2, 0, 1, 0, 0, 2, 0, 1, 1, 2, 1, 2, 0, 0, 1, 0, 0, 1, 0, -1, 1, 1, 0, 1,
0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 0,
# [batch_size,in_channels,high,width]
1, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0]).reshape([1, 3, 5, 5])
filters = torch.tensor([[[[2, 0, 0],
[1, 0, 1],
[0, 3, 0]],
[[1, 0, 1],
[0, 0, 0],
[1, 1, 0]],
[[0, 0, 1],
[1, 1, 1],
[1, 1, 0]]]]) # [1,3,3,3] [ [filter_nums/output_channels,input_channels,high,width]
bias = torch.tensor([1])
可以看到,对于inputs来说我们首先定义了75个值,然后再将其reshape成了图像的表示格式;而对于filters来说,我们在定义的时候就直接写成了框架所需要的形式。
接下来,我们仅仅只需要通过下面一行代码就能够完成对于卷积的计算过程:
result = F.conv2d(inputs, filters, bias=bias, stride=1, padding=0)
其中strid=1
表示移动一次的步长设为1,padding=0
表示不进行填充。
最后,计算得到的结果为:
卷积后的结果: tensor([[[[ 7, 18, 6],
[10